在官方的demo中,应该分为客户端和服务端两部分,
首先最重要的是客户端,可以分为五个步骤,
1. 获得本地的蓝牙适配器
BluetoothAdapter bluetoothAdapter;
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
2.开启蓝牙设备
bluetoothAdapter.enable();
3.搜索蓝牙设备地址
搜索的蓝牙设备是未配对过的,所以要先把配对过的先保存下来
private ArrayList<String> mPairedDevicesList = new ArrayList<String>();
Set<BluetoothDevice> pairedDevices = bluetoothAdapter.getBondedDevices();
for (BluetoothDevice device : pairedDevices) {
mPairedDevicesList.add("已配对:"+device.getName() + "\n" + device.getAddress());
}
然后注册两个广播,在搜索到新设备以及配对完成之后会接收到广播
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
registerReceiver(mReceiver, filter);
//当搜索完毕后注册广播
filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
registerReceiver(mReceiver, filter);
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
private ArrayList<String> mNewDevicesList = new ArrayList<String>();
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
// 当发现一个新的蓝牙设备时,将它记录下来
if (device.getBondState() != BluetoothDevice.BOND_BONDED) {
String s = "未配对: "+ device.getName() + "\n" + device.getAddress();
if(!mNewDevicesList.contains(s))
mNewDevicesList.add(s);
}
} else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
//当蓝牙搜索完时,列出所有设备,选择其中一个,并将address保存下来
}
}
};
4.请求连接地址
将获取到的address转换成device类型
BluetoothDevice device = bluetoothAdapter.getRemoteDevice(address);
ConnectThread connectThread = new ConnectThread(device);
connectThread.start();
然后开启一个线程,这个线程主要是建立一个socket
class ConnectThread extends Thread{
private final BluetoothSocket mmSocket;
public ConnectThread(BluetoothDevice device){
mmDevice = device;
BluetoothSocket tmp = null;
try {
tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
} catch (IOException e) {
e.printStackTrace();
}
mmSocket = tmp;
}
@Override
public void run() {
bluetoothAdapter.cancelDiscovery(); //先停止搜索
try {
mmSocket.connect();
} catch (IOException e) {
e.printStackTrace();
}
connectedTread = new ConnectedTread(mmSocket);
connectedTread.start();
}
}
这里无非做了两件事,一是通过UUID建立socket,第二是新建了另一个线程ConnectedThread这个后面会说
这里值得注意的是,UUID含义是通用唯一识别码,是一种用作识别一些硬件设备的编号,这里的UUID在客户端和服务端必须是同一个,不然无法建立连接!
这里使用默认MY_UUID
private static final UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
5.发送消息
这里通过IO流进行信息传输,IO流通过socket.getInputStream和socket.getOutputStream获得,那接下来的通讯就很简单了
class ConnectedTread extends Thread {
private final BluetoothSocket mmSocket;
private final InputStream mmInStream;
private final OutputStream mmOutStream;
public ConnectedTread(BluetoothSocket socket) {
mmSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) {
e.printStackTrace();
}
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
@Override
public void run() {
byte[] buffer = new byte[1024];
int bytes;
while (true){
try {
bytes = mmInStream.read(buffer);
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(ClientActivity.this, "连接断开", Toast.LENGTH_SHORT).show();
break;
}
}
}
public void write(byte[] buffer){
try {
mmOutStream.write(buffer);
} catch (IOException e) {
e.printStackTrace();
}
}
}
服务端:
服务端也特别简单,我们看客户端使用的socket可以知道,服务端主要的操作便是开启一个serverSocket,然后等待连接访问。
说到底其实蓝牙通讯就是建立一个socket通讯的过程,这样看的话就很好理解了。
而且IO通讯在服务端完全可以通用,在demo中甚至将这两部分用同一个ConnectedThread来实现
我们来看看服务端需要做些什么
private AcceptThread acceptThread;
isRunning = true;
//开启服务器
acceptThread = new AcceptThread();
acceptThread.start();
private class AcceptThread extends Thread{
private final BluetoothServerSocket mServerSocket;
private BluetoothSocket socket;
public AcceptThread() {
BluetoothServerSocket tmp = null;
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
// Create a new listening server socket
try {
tmp = bluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);//注意这里的MY_UUID与客户端的要保持一致
} catch (IOException e) {
Log.e("sxd", " ======== ufcomm exception =======" , e);
}
mServerSocket = tmp;
}
@Override
public void run() {
super.run();
while (true){
if (isRunning)
try {
socket = mServerSocket.accept();
connectedTread = new ConnectedTread(socket);
connectedTread.start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public void close(){
isRunning = false;
try {
mServerSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
循环监听是否有连接访问,当获得一个socket则表示连接通过,开启IO流进行传输,connectedThread与上面的一致