共计 5708 个字符,预计需要花费 15 分钟才能阅读完成。
-
应用蓝牙的响应权限
<uses-permission android:name="android.permission.BLUETOOTH"/> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
-
配置本机蓝牙模块
在这里首先要理解对蓝牙操作一个外围类 BluetoothAdapterBluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); // 间接关上零碎的蓝牙设置面板 Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(intent, 0x1); // 间接关上蓝牙 adapter.enable(); // 敞开蓝牙 adapter.disable(); // 关上本机的蓝牙发现性能(默认关上 120 秒,能够将工夫最多缩短至 300 秒)Intent discoveryIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE); discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);// 设置持续时间(最多 300 秒)
3. 搜寻蓝牙设施
应用 BluetoothAdapter 的 startDiscovery()办法来搜寻蓝牙设施
startDiscovery() 办法是一个异步办法,调用后会立刻返回。该办法会进行对其余蓝牙设施的搜寻,该过程会继续 12 秒。该办法调用后,搜寻过程实际上是在一个 System Service 中进行的,所以能够调用 cancelDiscovery()办法来进行搜寻(该办法能够在未执行 discovery 申请时调用)。
申请 Discovery 后,零碎开始搜寻蓝牙设施,在这个过程中,零碎会发送以下三个播送:
ACTION_DISCOVERY_START:开始搜寻
ACTION_DISCOVERY_FINISHED:搜寻完结
ACTION_FOUND:找到设施,这个 Intent 中蕴含两个 extra fields:EXTRA_DEVICE 和 EXTRA_CLASS,别离蕴含 BluetooDevice 和 BluetoothClass。
咱们能够本人注册相应的 BroadcastReceiver 来接管响应的播送,以便实现某些性能// 创立一个接管 ACTION_FOUND 播送的 BroadcastReceiver private final BroadcastReceiver mReceiver = new BroadcastReceiver() {public void onReceive(Context context, Intent intent) {String action = intent.getAction(); // 发现设施 if (BluetoothDevice.ACTION_FOUND.equals(action)) { // 从 Intent 中获取设施对象 BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); // 将设施名称和地址放入 array adapter,以便在 ListView 中显示 mArrayAdapter.add(device.getName() + "\n" + device.getAddress()); } } }; // 注册 BroadcastReceiver IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND); registerReceiver(mReceiver, filter); // 不要忘了之后解除绑定
- 蓝牙 Socket 通信
如果打算倡议两个蓝牙设施之间的连贯,则必须实现服务器端与客户端的机制。当两个设施在同一个 RFCOMM channel 下别离领有一个连贯的 BluetoothSocket,这两个设施才能够说是建设了连贯。
服务器设施与客户端设施获取 BluetoothSocket 的路径是不同的。服务器设施是通过 accepted 一个 incoming connection 来获取的,而客户端设施则是通过关上一个到服务器的 RFCOMM channel 来获取的。
服务器端的实现
通过调用 BluetoothAdapter 的 listenUsingRfcommWithServiceRecord(String, UUID)办法来获取 BluetoothServerSocket(UUID 用于客户端与服务器端之间的配对)
调用 BluetoothServerSocket 的 accept()办法监听连贯申请,如果收到申请,则返回一个 BluetoothSocket 实例(此办法为 block 办法,应置于新线程中)
如果不想在 accept 其余的连贯,则调用 BluetoothServerSocket 的 close()办法开释资源(调用该办法后,之前取得的 BluetoothSocket 实例并没有 close。但因为 RFCOMM 一个时刻只容许在一条 channel 中有一个连贯,则个别在 accept 一个连贯后,便 close 掉 BluetoothServerSocket)
private class AcceptThread extends Thread {
private final BluetoothServerSocket mmServerSocket;
public AcceptThread() {
// Use a temporary object that is later assigned to mmServerSocket,
// because mmServerSocket is final
BluetoothServerSocket tmp = null;
try {
// MY_UUID is the app's UUID string, also used by the client code
tmp = mBluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);
} catch (IOException e) { }
mmServerSocket = tmp;
}
public void run() {
BluetoothSocket socket = null;
// Keep listening until exception occurs or a socket is returned
while (true) {
try {socket = mmServerSocket.accept();
} catch (IOException e) {break;}
// If a connection was accepted
if (socket != null) {// Do work to manage the connection (in a separate thread)
manageConnectedSocket(socket);
mmServerSocket.close();
break;
}
}
}
/** Will cancel the listening socket, and cause the thread to finish */
public void cancel() {
try {mmServerSocket.close();
} catch (IOException e) {}}
}
客户端的实现
通过搜寻失去服务器端的 BluetoothService
调用 BluetoothService 的 listenUsingRfcommWithServiceRecord(String, UUID)办法获取 BluetoothSocket(该 UUID 应该同于服务器端的 UUID)
调用 BluetoothSocket 的 connect()办法(该办法为 block 办法),如果 UUID 同服务器端的 UUID 匹配,并且连贯被服务器端 accept,则 connect()办法返回
留神:在调用 connect()办法之前,该当确定以后没有搜寻设施,否则连贯会变得十分慢并且容易失败
private class ConnectThread extends Thread { private final BluetoothSocket mmSocket;
private final BluetoothDevice mmDevice;
public ConnectThread(BluetoothDevice device) {
// Use a temporary object that is later assigned to mmSocket,
// because mmSocket is final
BluetoothSocket tmp = null;
mmDevice = device;
// Get a BluetoothSocket to connect with the given BluetoothDevice
try {
// MY_UUID is the app's UUID string, also used by the server code
tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
} catch (IOException e) { }
mmSocket = tmp;
}
public void run() {
// Cancel discovery because it will slow down the connection
mBluetoothAdapter.cancelDiscovery();
try {
// Connect the device through the socket. This will block
// until it succeeds or throws an exception
mmSocket.connect();} catch (IOException connectException) {
// Unable to connect; close the socket and get out
try {mmSocket.close();
} catch (IOException closeException) { }
return;
}
// Do work to manage the connection (in a separate thread)
manageConnectedSocket(mmSocket);
}
/** Will cancel an in-progress connection, and close the socket */
public void cancel() {
try {mmSocket.close();
} catch (IOException e) {}}
}
4. 连贯治理(数据通信)
别离通过 BluetoothSocket 的 getInputStream()和 getOutputStream()办法获取 InputStream 和 OutputStream
应用 read(bytes[])和 write(bytes[])办法别离进行读写操作
留神:read(bytes[])办法会始终 block,晓得从流中读取到信息,而 write(bytes[])办法并不是常常的 block(比方在另一设施没有及时 read 或者两头缓冲区已满的状况下,write 办法会 block)
private class ConnectedThread extends Thread {
private final BluetoothSocket mmSocket;
private final InputStream mmInStream;
private final OutputStream mmOutStream;
public ConnectedThread(BluetoothSocket socket) {
mmSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
// Get the input and output streams, using temp objects because
// member streams are final
try {tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();} catch (IOException e) { }
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
public void run() {byte[] buffer = new byte[1024]; // buffer store for the stream
int bytes; // bytes returned from read()
// Keep listening to the InputStream until an exception occurs
while (true) {
try {
// Read from the InputStream
bytes = mmInStream.read(buffer);
// Send the obtained bytes to the UI Activity
mHandler.obtainMessage(MESSAGE_READ, bytes, -1, buffer)
.sendToTarget();} catch (IOException e) {break;}
}
}
/* Call this from the main Activity to send data to the remote device */
public void write(byte[] bytes) {
try {mmOutStream.write(bytes);
} catch (IOException e) {}}
/* Call this from the main Activity to shutdown the connection */
public void cancel() {
try {mmSocket.close();
} catch (IOException e) {}}
}