题引:
最近项目上涉及与硬件相关的功能,需要通过蓝牙进行消息收发。项目已完成,这里做下记录。
通信步骤:
1.初始化BluetoothAdapter.getDefaultAdapter()获取BluetoothAdapter对象
2.判断蓝牙是否开启bluetoothAdapter.isEnabled()
3.未开启,进行开启操作bluetoothAdapter.enable();有返回值,为true证明开启成功
4.注册蓝牙开关广播 BluetoothAdapter.ACTION_STATE_CHANGED 监听开关等状态
5.搜索蓝牙设备 bluetoothAdapter.startDiscovery();
6.点击对配,需要判断是是否有过配对,有则连接;无则配对
7.依据广播状态改变文字描述BluetoothDevice.ACTION_BOND_STATE_CHANGED
8.配对成功,自动连接需要开子线程device.getClass().getMethod("createRfcommSocket", new Class[]{int.class}).invoke(device, 1);
9.监听连接广播,成功开启子线程接收数据,失败点击重连
10.开启子线程发送消息
1.开启或关闭蓝牙
1.1通过BluetoothAdapter.getDefaultAdapter();拿到蓝牙适配器,其中isEnabled()可直接返回当前蓝牙状态。
/*** 获取蓝牙开关状态** @return true为开,false为关*/public boolean getBluetoothSwitchState() {if (bluetoothAdapter != null) {return bluetoothAdapter.isEnabled();}return false;}
1.2返回为false时,蓝牙处于关闭状态。通过bluetoothAdapter.enable();方法打开蓝牙,同样,bluetoothAdapter.disable();方法可关闭蓝牙。这两个方法均有返回值,可通过返回值判断是否开启成功!
/*** 开启蓝牙设备** @return 开启是否成功*/public boolean startBlueTooth() {if (bluetoothAdapter == null) {return false;}return bluetoothAdapter.enable();}/*** 关闭蓝牙*/public void closeBlueToothDevice() {if (bluetoothAdapter == null) {return;}bluetoothAdapter.disable();}
1.3 注意:用户可将程序挂起,从设置页或下拉状态栏进行打开关闭蓝牙。如蓝牙关闭,此时APP需要通过广播进行监听,关闭则提示用户打开蓝牙,或退出程序。我讲所需要的广播先都提前写出!
receiver = new BluetoothReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED); //监听蓝牙关闭和打开状态
filter.addAction(BluetoothDevice.ACTION_FOUND); //搜索发现设备
filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED); //搜索完毕
filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED); //配对状态
filter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);//蓝牙连接成功
filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED); //蓝牙连接失败context.registerReceiver(receiver, filter);
2. 设备搜索
2.1 蓝牙开启后,自动进行设备搜索
/*** 搜索蓝牙设备
*/
public void searchBluetooth() {if (bluetoothAdapter == null) {return;}bluetoothAdapter.startDiscovery();
}
2.2广播监听搜索到的设备,进行列表展示(单个设备引入第二个重要类BluetoothDevice)
注意:搜索到设备可能存在空值,或重复搜索。需要自己在adpter或list中筛选。
2.3蓝牙搜索会后自动停止,对应停止广播BluetoothAdapter.ACTION_DISCOVERY_FINISHED:可在停止后进行配对,若没有扫描到对应设备则再次进行重新搜索
3.蓝牙配对
3.1蓝牙连接分配对与连接两个过程,如果未配对,则必须先进行配对,如果之前配对成功,并且没有取消配对,可直接进行连接;有三个参数,可判断对应设备与当前设备之间的关联
3.2 假设之前配对成功,该设备device.getBondState()为BOND_BONDED,以此来判断是否配对
/**
* 是否配对过
*
* @param device 设备信息
* @return true是 false否
*/
public boolean isPaired(BluetoothDevice device) {if (device.getBondState() == BluetoothDevice.BOND_BONDED) {return true;}return false;
}
3.3.1配过对直接连接,当前写未配对情况。配对代码:
/**
* 对蓝牙进行配对(反射调用,需自行刷新数据)
*
* @param device 设备信息
*/
public void pairBluetoothDevice(BluetoothDevice device) {try {Method method = BluetoothDevice.class.getMethod("createBond");method.invoke(device);} catch (Exception e) {LogUtils.error("pairBluetoothDeviceException : {}", e.getMessage());}
}
3.3.2 既然可以配对,当前可取消配对,将取消配对代码也给出:需要先判断下,之前是否配对成功,条件同3.2;
/*** 取消该蓝牙配对(反射调用,需自行刷新数据)** @param device 设备信息*/public void canlePairBluetoothDevice(BluetoothDevice device) {try {Method method = BluetoothDevice.class.getMethod("removeBond");method.invoke(device);} catch (Exception e) {LogUtils.error("canlePairBluetoothDeviceException : {}", e.getMessage());}}
3.4 配对状态通过广播监听,监听后,改变状态展示给用户
3.5 参照系统蓝牙配对成功后需要自己连接设备。失败则刷新adapter,更新至最新状态等待用户下一步操作。
4.蓝牙连接
4.1蓝牙连接代码:(需要在子线程中操作)
/*** 连接设备** @param device 设备信息*/public void connBluetoothDevice(BluetoothDevice device) {new Thread() {@Overridepublic void run() {super.run();try {mBluetoothSocket = (BluetoothSocket) device.getClass().getMethod("createRfcommSocket", new Class[]{int.class}).invoke(device, 1);if (mBluetoothSocket != null) {if (!mBluetoothSocket.isConnected()) {mBluetoothSocket.connect();}}} catch (Exception e) {LogUtils.error("connectException:{}", e.getMessage());mBluetoothSocket = null;}}}.start();}
4.2连接成功或失败在广播中进行监听
4.3成功,需要开启子线程进行数据接收操作,失败,自行处理;
/*** 接收消息** @param consumer 数据回调*/public void reviceMsg(Consumer<String> consumer) {if (mBluetoothSocket == null) {LogUtils.error("reviceMsg socket is null");return;}new Thread() {@Overridepublic void run() {super.run();while (true) {char [] buffer = new char[1024];try {InputStream is = mBluetoothSocket.getInputStream();InputStreamReader inputStreamReader = new InputStreamReader(is, "GBK");int read = inputStreamReader.read(buffer);String readStr = new String(buffer, 0, read);LogUtils.info("reviceMsg:Msg ={};",readStr);consumer.accept(readStr);
// is.close();
// bluetoothSocket.close();} catch (Exception e) {LogUtils.error("reviceMsgException: {}", e.getMessage());}}}}.start();}
4.4 同理,连接成功也需要像对应设备发送消息,代码如下:
/*** 发送消息** @param msg 数据*/public void sendMsg(int msg) {if (mBluetoothSocket == null) {LogUtils.error("sendMsg socket is null");return;}new Thread() {@Overridepublic void run() {super.run();try {byte[] buffer = Integer.toHexString(msg).getBytes();OutputStream outputStream = mBluetoothSocket.getOutputStream();outputStream.write(buffer);outputStream.flush();LogUtils.info("sendMsg msg = {}",Integer.toHexString(msg));} catch (Exception e) {LogUtils.error("sendMsgException : {}", e.getMessage());}}}.start();}
5.后记
至此,蓝牙通信功能基本实现,其中需要在清单文件配置权限,在此给出;目前还不知道怎么网CSDN放自己的代码类,回头知道了进行补齐!
<uses-permission android:name="android.permission.BLUETOOTH" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /><uses-permission android:name="android.permission.BLUETOOTH_CONNECT" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
6.补充
上面蓝牙开启时会弹出一个询问是否想要开启蓝牙,如果选择拒接是没有回调的。处理不友好,查阅资料发现有个带回调的开启蓝牙方法贴出:
public void startBlueToothCallBack(Activity activity){if (bluetoothAdapter == null) {return;}if (!bluetoothAdapter.isEnabled()) {Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);activity.startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);}}
在onActivityResult中进行回调操作:
@Overrideprotected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {super.onActivityResult(requestCode, resultCode, data);if (requestCode == BluetoothUtils.getInstance().REQUEST_ENABLE_BT && resultCode == RESULT_OK) {//蓝牙已开启searchBluetooth();} else {finish();}}