如果各位觉得有用,转载+个出处。
现如今安卓的低功耗蓝牙应用十分普遍了,智能手环、手表遍地都是,基本都是利用BLE通信来交互数据。BLE基本在安卓、IOS两大终端设备上都有很好支持,所以有很好发展前景。
现市面上各种手环、手表的智能设备中基本都充当"从设备"这样的角色,基本由智能设备完成蓝牙广播,由手机进行连接,然后交互数据。
根据上述方式的应用在安卓4.3、IOS 7.0的版本上就得到了支持,应用也比较广泛,园里应该有很多相关实现,大家可以自己找找,如果不愿意找,抽空再写一篇。
今天主要是为了说在安卓5.0时升级了广播相关API,园里也有一些说明,但之所以还写这篇是因为数据交换的提及很少。
既然将手机要做广播了,那么实质手机就变成手环、手表的角色,一个从设备了。
如果你愿意,可以拿另一台手机做个主设备,这样他们就可以交流了。
好了,我们进入代码正题吧...
首先应用权限设置。在AndroidManifest.xml中还是要加入BLE控制权限,不然异常一定与你为伍。
1 <uses-permission android:name="android.permission.BLUETOOTH" /> 2 <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
接着我们上套路了,判断手机是否支持BLE以及是否支持BLE从设备。
1 if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) { 2 showToast("该设备不支持蓝牙低功耗通讯"); 3 this.finish(); 4 return; 5 } 6 7 bluetoothManager = (BluetoothManager) getSystemService(BLUETOOTH_SERVICE); 8 9 bluetoothAdapter = bluetoothManager.getAdapter(); 10 11 if (bluetoothAdapter == null) { 12 showToast("该设备不支持蓝牙低功耗通讯"); 13 this.finish(); 14 return; 15 } 16 17 bluetoothLeAdvertiser = bluetoothAdapter.getBluetoothLeAdvertiser(); 18 if (bluetoothLeAdvertiser == null) { 19 showToast("该设备不支持蓝牙低功耗从设备通讯"); 20 this.finish(); 21 return; 22 }
我建议你先拿你调试设备试试,大多数同学走到这里都绝望了。你问我为啥?你试试就知道了。
如果你一脸what???的话,那恭喜你,你的调试设备是被选中的孩子,让我们继续乘风破浪吧。顺便在评论里告诉我下你用啥设备哦。
这时候我们开启广播的旋风吧。
1 //广播设置 2 AdvertiseSettings.Builder settingBuilder = new AdvertiseSettings.Builder(); 3 settingBuilder.setConnectable(true); 4 settingBuilder.setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_BALANCED); 5 settingBuilder.setTimeout(0); //我填过别的,但是不能广播。后来我就坚定的0了 6 settingBuilder.setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_HIGH); 7 AdvertiseSettings settings = settingBuilder.build(); 8 9 10 //广播参数 11 AdvertiseData.Builder dataBuilder = new AdvertiseData.Builder(); 12 bluetoothAdapter.setName("H8-BlePpl"); //你想叫啥名字,你愿意就好 13 dataBuilder.setIncludeDeviceName(true); 14 dataBuilder.setIncludeTxPowerLevel(true); 15 16 dataBuilder.addServiceUuid(ParcelUuid.fromString(Const.UUID_SERVICE)); //可自定义UUID,看看官方有没有定义哦 17 AdvertiseData data = dataBuilder.build(); 18 19 bluetoothLeAdvertiser.startAdvertising(settings, data, advertiseCallback);
然后你的小手机就开始广播了,说大家来连我啊连我啊。别总搜地址,貌似地址动态会变的,还是用名儿吧毕竟你起了啊。
我之前傻傻的查了手机蓝牙MAC地址,后来发现不是广播的那个...
广播回调我干了点新增服务的活儿,不干你拿啥通信来。
1 private AdvertiseCallback advertiseCallback = new AdvertiseCallback() { 2 @Override 3 public void onStartSuccess(AdvertiseSettings settingsInEffect) { 4 super.onStartSuccess(settingsInEffect); 5 runOnUiThread(new Runnable() { 6 @Override 7 public void run() { 8 showInfo("1.1 AdvertiseCallback-onStartSuccess"); 9 } 10 }); 11 12 13 bluetoothGattServer = bluetoothManager.openGattServer(getApplicationContext(), 14 bluetoothGattServerCallback); 15 16 BluetoothGattService service = new BluetoothGattService(UUID.fromString(Const.UUID_SERVICE), 17 BluetoothGattService.SERVICE_TYPE_PRIMARY); 18 19 UUID UUID_CHARREAD = UUID.fromString(Const.UUID_CHARACTERISTIC); 20 21 //特征值读写设置 22 BluetoothGattCharacteristic characteristicWrite = new BluetoothGattCharacteristic(UUID_CHARREAD, 23 BluetoothGattCharacteristic.PROPERTY_WRITE | 24 BluetoothGattCharacteristic.PROPERTY_READ | 25 BluetoothGattCharacteristic.PROPERTY_NOTIFY, 26 BluetoothGattCharacteristic.PERMISSION_WRITE); 27 28 UUID UUID_DESCRIPTOR = UUID.fromString(Const.UUID_CHARACTERISTIC_CONFIG); 29 30 BluetoothGattDescriptor descriptor = new BluetoothGattDescriptor(UUID_DESCRIPTOR, BluetoothGattCharacteristic.PERMISSION_WRITE); 31 characteristicWrite.addDescriptor(descriptor); 32 service.addCharacteristic(characteristicWrite); 33 34 bluetoothGattServer.addService(service); 35 36 37 runOnUiThread(new Runnable() { 38 @Override 39 public void run() { 40 showInfo("1.2. Service Builded ok"); 41 } 42 }); 43 44 }};
当你收到广播成功回调后,来吧,特征值啊~~反正要通信呐~~
被你发现了我偷懒读写特征值用了一个,其实你愿意用两个就用两个吧。
我用的NOTIFICATION方式做主设备的读取,你也可用INDICATION方式做。
服务建立完成后,也会收到通知。BLE嘛~~都是异步回调~~我是习惯了!
1 private BluetoothGattServerCallback bluetoothGattServerCallback = new BluetoothGattServerCallback() { 2 @Override 3 public void onServiceAdded(int status, BluetoothGattService service) { 4 super.onServiceAdded(status, service); 5 6 final String info = service.getUuid().toString(); 7 runOnUiThread(new Runnable() { 8 @Override 9 public void run() { 10 showInfo("1.3 BluetoothGattServerCallback-onServiceAdded " + info); 11 } 12 }); 13 14 15 } 16 17 @Override 18 public void onConnectionStateChange(BluetoothDevice device, int status, int newState) { 19 super.onConnectionStateChange(device, status, newState); 20 final String info = device.getAddress() + "|" + status + "->" + newState; 21 22 runOnUiThread(new Runnable() { 23 @Override 24 public void run() { 25 showInfo("1.4 onConnectionStateChange " + info); 26 } 27 }); 28 } 29 30 @Override 31 public void onCharacteristicReadRequest(BluetoothDevice device, int requestId, int offset, 32 BluetoothGattCharacteristic characteristic) { 33 super.onCharacteristicReadRequest(device, requestId, offset, characteristic); 34 35 36 final String deviceInfo = "Address:" + device.getAddress(); 37 final String info = "Request:" + requestId + "|Offset:" + offset + "|characteristic:" + characteristic.getUuid() + "|Value:" + 38 Util.bytes2HexString(characteristic.getValue()); 39 40 runOnUiThread(new Runnable() { 41 @Override 42 public void run() { 43 44 showInfo("============================================="); 45 showInfo("设备信息 " + deviceInfo); 46 showInfo("数据信息 " + info); 47 showInfo("=========onCharacteristicReadRequest========="); 48 49 } 50 }); 51 52 bluetoothGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, characteristic.getValue()); 53 54 } 55 56 @Override 57 public void onCharacteristicWriteRequest(BluetoothDevice device, int requestId, BluetoothGattCharacteristic characteristic, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) { 58 super.onCharacteristicWriteRequest(device, requestId, characteristic, 59 preparedWrite, responseNeeded, offset, value); 60 61 final String deviceInfo = "Name:" + device.getAddress() + "|Address:" + device.getAddress(); 62 final String info = "Request:" + requestId + "|Offset:" + offset + "|characteristic:" + characteristic.getUuid() + "|Value:" + Util.bytes2HexString(value); 63 64 65 bluetoothGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, value); 66 //TODO:你做数据处理 67 68 69 runOnUiThread(new Runnable() { 70 @Override 71 public void run() { 72 73 showInfo("============================================="); 74 showInfo("设备信息 " + deviceInfo); 75 showInfo("数据信息 " + info); 76 showInfo("=========onCharacteristicWriteRequest========="); 77 78 } 79 }); 80 81 82 } 83 84 85 @Override 86 public void onNotificationSent(BluetoothDevice device, int status) { 87 super.onNotificationSent(device, status); 88 89 final String info = "Address:" + device.getAddress() + "|status:" + status; 90 91 runOnUiThread(new Runnable() { 92 @Override 93 public void run() { 94 showInfo("onNotificationSent " + info); 95 } 96 }); 97 } 98 99 100 @Override 101 public void onDescriptorWriteRequest(BluetoothDevice device, int requestId, BluetoothGattDescriptor descriptor, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) { 102 final String deviceInfo = "Name:" + device.getAddress() + "|Address:" + device.getAddress(); 103 final String info = "Request:" + requestId + "|Offset:" + offset + "|characteristic:" + descriptor.getUuid() + "|Value:" + Util.bytes2HexString(value); 104 105 runOnUiThread(new Runnable() { 106 @Override 107 public void run() { 108 109 showInfo("============================================="); 110 showInfo("设备信息 " + deviceInfo); 111 showInfo("数据信息 " + info); 112 showInfo("=========onDescriptorWriteRequest========="); 113 114 } 115 }); 116 117 118 // 告诉连接设备做好了 119 bluetoothGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, value); 120 } 121 122 @Override 123 public void onDescriptorReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattDescriptor descriptor) { 124 125 super.onDescriptorReadRequest(device, requestId, offset, descriptor); 126 127 final String deviceInfo = "Name:" + device.getAddress() + "|Address:" + device.getAddress(); 128 final String info = "Request:" + requestId + "|Offset:" + offset + "|characteristic:" + descriptor.getUuid(); 129 130 131 runOnUiThread(new Runnable() { 132 @Override 133 public void run() { 134 135 showInfo("============================================="); 136 showInfo("设备信息 " + deviceInfo); 137 showInfo("数据信息 " + info); 138 showInfo("=========onDescriptorReadRequest========="); 139 140 } 141 }); 142 143 // 告诉连接设备做好了 144 bluetoothGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, null); 145 146 147 } 148 149 };
基本上从设备就做完了。
调试的时候你用主设备查服务列表可能查不到你的UUID_SERVICE,但是别慌,你getServcie(UUID_SERVICE)试试,说不定就柳暗花明了。
还有就是我拿的华为Honor 8做的调试机子,其他还有啥型号请各位分享下。姑娘我跪谢啦~~