Android 蓝牙开发
<h2>Android 蓝牙开发</h2><p>我们在进行蓝牙开发时首先要了解低功耗蓝牙、经典蓝牙、单模蓝牙、双模蓝牙之间的关系。<br>单模蓝牙:支持低功耗蓝牙<br>双模蓝牙:支持低功耗蓝牙和经典蓝牙<br>经典蓝牙:支持经典蓝牙<br>蓝牙开发大致分为这几步<br><br></p>
<p>前面需要定位权限和蓝牙权限的支持</p>
<p><span style="font-size: 16px"><strong>发现设备:</strong></span></p>
<p>经典蓝牙发现设备api<br>BluetoothAdapter.startDiscovery<br>听说可以同时发现经典蓝牙和低功耗蓝牙(BLE)。但我这没单模的蓝牙,所以没办法测试。<br>因为startDiscovery返回的是一个是否开始扫描设备,我们要获取蓝牙设备的信息需要注册一个 BroadcastReceiver 针对 ACTION_FOUND <br>Intent 会携带额外的字段 EXTRA_DEVICE 和 EXTRA_CLASS。这两者分别包含 BluetoothDevice 和 BluetoothClass。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">var</span> filter =<span style="color: rgba(0, 0, 0, 1)">IntentFilter(BluetoothDevice.ACTION_FOUND);
registerReceiver(mReceiver,filter);
val mReceiver </span>=<span style="color: rgba(0, 0, 0, 1)"> object :BroadcastReceiver(){
override fun onReceive(context: Context</span>?, intent: Intent?<span style="color: rgba(0, 0, 0, 1)">) {
</span><span style="color: rgba(0, 0, 255, 1)">var</span> action = intent?<span style="color: rgba(0, 0, 0, 1)">.action
</span><span style="color: rgba(0, 0, 255, 1)">if</span>(BluetoothDevice.ACTION_FOUND ==<span style="color: rgba(0, 0, 0, 1)"> action){
</span><span style="color: rgba(0, 0, 255, 1)">var</span> device = intent?.getParcelableExtra<BluetoothDevice><span style="color: rgba(0, 0, 0, 1)">(BluetoothDevice.EXTRA_DEVICE)
}
}
}
override fun onDestroy() {
super.onDestroy()
unregisterReceiver(mReceiver)
} </span></pre>
</div>
<p>Ble发现设备api<br>BluetoothAdapter.getBluetoothLeScanner()<br>BluetoothLeScanner.startScan(ScanCallback callback)//扫描会在屏幕关闭时停止以节省电量。 再次打开屏幕时,将恢复扫描。 为避免这种情况,请使用下面两个<br>BluetoothLeScanner.startScan(List<ScanFilter> filters, ScanSettings settings, ScanCallback callback)<br>BluetoothLeScanner.startScan(List<ScanFilter> filters, ScanSettings settings, PendingIntent callbackIntent)</p>
<div class="cnblogs_code">
<pre>BluetoothLeScanner bluetoothLeScanner =<span style="color: rgba(0, 0, 0, 1)"> bluetoothAdapter.getBluetoothLeScanner();
filters.add(</span><span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> ScanFilter.Builder()
.setServiceUuid(ParcelUuid.fromString(</span>"0000000-0000-0000-0000-000000000000"<span style="color: rgba(0, 0, 0, 1)">))
.build());
bluetoothLeScanner.startScan(filters , </span><span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> ScanSettings.Builder().build(),
</span><span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> ScanCallback() {
@Override
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span> onScanResult(<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> callbackType, ScanResult result) {
</span><span style="color: rgba(0, 0, 255, 1)">super</span><span style="color: rgba(0, 0, 0, 1)">.onScanResult(callbackType, result);
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (Build.VERSION.SDK_INT >=<span style="color: rgba(0, 0, 0, 1)"> Build.VERSION_CODES.O) {
Log.d(MainActivity.ACTIVITY_SERVICE, </span>"onScanResult:"+
"\n Rssi() "+result.getRssi()+
"\n AdvertisingSid() "+result.getAdvertisingSid()+
"\n DataStatus() "+result.getDataStatus()+
"\n ScanRecord() "+result.getScanRecord().getBytes()+
"\n Address() "+result.getDevice().getAddress()+
"\n Address() "+<span style="color: rgba(0, 0, 0, 1)">result.getDevice().getName()
);
}
}
@Override
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span> onBatchScanResults(List<ScanResult><span style="color: rgba(0, 0, 0, 1)"> results) {
</span><span style="color: rgba(0, 0, 255, 1)">super</span><span style="color: rgba(0, 0, 0, 1)">.onBatchScanResults(results);
}
@Override
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span> onScanFailed(<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> errorCode) {
</span><span style="color: rgba(0, 0, 255, 1)">super</span><span style="color: rgba(0, 0, 0, 1)">.onScanFailed(errorCode);
}
}
);</span></pre>
</div>
<p> </p>
<p><span style="font-size: 16px"><strong>建立连接:</strong></span></p>
<p>在配对之前应该先cancelDiscovery()或者stopScan(callback),<br>然后根据获取到蓝牙Mac地址连接即可</p>
<div class="cnblogs_code">
<pre>BluetoothDevice device =<span style="color: rgba(0, 0, 0, 1)"> bluetoothAdapter.getRemoteDevice(result.getDevice().getAddress());
device.connectGatt(MainActivity.</span><span style="color: rgba(0, 0, 255, 1)">this</span>, <span style="color: rgba(0, 0, 255, 1)">false</span>, <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> BluetoothGattCallback() {
@Override
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span> onConnectionStateChange(BluetoothGatt gatt, <span style="color: rgba(0, 0, 255, 1)">int</span> status, <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> newState) {
</span><span style="color: rgba(0, 0, 255, 1)">super</span><span style="color: rgba(0, 0, 0, 1)">.onConnectionStateChange(gatt, status, newState);
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">status 连接或断开连接操作成功 BluetoothGatt.GATT_SUCCESS(0)
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">newState 新的连接状态 BluetoothProfile.STATE_DISCONNECTED(0-断开状态) BluetoothProfile.STATE_CONNECTED(1-连接状态)</span>
<span style="color: rgba(0, 0, 0, 1)"> }
}
);</span></pre>
</div>
<p> </p>
<p><strong><span style="font-size: 16px">数据通信:<br></span></strong>ble写入操作</p>
<div class="cnblogs_code">
<pre> <span style="color: rgba(0, 0, 255, 1)">private</span> BluetoothGattCallback bluetoothGattCallback = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> BluetoothGattCallback() {
@Override
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span> onConnectionStateChange(BluetoothGatt gatt, <span style="color: rgba(0, 0, 255, 1)">int</span> status, <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> newState) {
</span><span style="color: rgba(0, 0, 255, 1)">super</span><span style="color: rgba(0, 0, 0, 1)">.onConnectionStateChange(gatt, status, newState);
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">status 连接或断开连接操作成功 BluetoothGatt.GATT_SUCCESS(0)
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">newState 新的连接状态 BluetoothProfile.STATE_DISCONNECTED(0-断开状态) BluetoothProfile.STATE_CONNECTED(1-连接状态)
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">获取远程设备提供的服务以及它们的特征和描述符。这步很重要而且是一个异步操作(这里需要时间直接接在下面写不可取)</span>
<span style="color: rgba(0, 0, 0, 1)"> bluetoothGatt.discoverServices();
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">获取蓝牙GATT服务</span>
BluetoothGattService gattService = bluetoothGatt.getService(UUID.fromString("00000000-0000-0000-0000-000000000000"<span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">蓝牙协议</span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">));
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">GATT特性:用于构建 GATT 服务的基本数据元素</span>
BluetoothGattCharacteristic characteristic = gattService.getCharacteristic(UUID.fromString("00000000-0000-0000-0000-000000000000"<span style="color: rgba(0, 0, 0, 1)">));
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">设置数据,这里是我加密后的数据所以看起来有点不习惯</span>
<span style="color: rgba(0, 0, 255, 1)">byte</span>[] data = {-27, 36, 65, -70, -8, 94, 18, -12, -56, 116, -68, -124, 92, -19, 94, -91<span style="color: rgba(0, 0, 0, 1)"> };
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">设置此特性的本地存储值。</span>
<span style="color: rgba(0, 0, 0, 1)"> characteristic.setValue(data);
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">写入到远程蓝牙设备</span>
<span style="color: rgba(0, 0, 0, 1)"> bluetoothGatt.writeCharacteristic(characteristic);
}</span></pre>
</div>
<p> Ble通知读取操作</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">通知UUID</span>
BluetoothGattCharacteristic gattCharacteristic = gattService.getCharacteristic(UUID.fromString("00000000-0000-0000-0000-000000000000"<span style="color: rgba(0, 0, 0, 1)">));
enableNotification(bluetoothGatt,</span><span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">,gattCharacteristic);
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span> enableNotification(BluetoothGatt bluetoothGatt, <span style="color: rgba(0, 0, 255, 1)">boolean</span><span style="color: rgba(0, 0, 0, 1)"> enable, BluetoothGattCharacteristic characteristic) {
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (bluetoothGatt == <span style="color: rgba(0, 0, 255, 1)">null</span> || characteristic == <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">) {
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">;
}
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (!<span style="color: rgba(0, 0, 0, 1)">bluetoothGatt.setCharacteristicNotification(characteristic, enable)) {
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">;
}
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">获取到Notify当中的Descriptor通道然后再进行注册</span>
List<BluetoothGattDescriptor> clientConfigs =<span style="color: rgba(0, 0, 0, 1)"> characteristic.getDescriptors();
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (clientConfigs == <span style="color: rgba(0, 0, 255, 1)">null</span> || clientConfigs.size() ==0<span style="color: rgba(0, 0, 0, 1)">) {
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">;
}
</span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (enable) {
</span><span style="color: rgba(0, 0, 255, 1)">for</span><span style="color: rgba(0, 0, 0, 1)"> (BluetoothGattDescriptor clientConfig: clientConfigs) {
clientConfig.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
bluetoothGatt.writeDescriptor(clientConfig);
}
} </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 0, 255, 1)">for</span><span style="color: rgba(0, 0, 0, 1)"> (BluetoothGattDescriptor clientConfig: clientConfigs) {
clientConfig.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
bluetoothGatt.writeDescriptor(clientConfig);
}
}
}</span></pre>
</div>
<p> </p><br><br>
来源:https://www.cnblogs.com/javaktolin/p/15459732.html
頁:
[1]