自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

一篇了解 BLE 藍(lán)牙開發(fā)詳解

移動(dòng)開發(fā) Android
Android 4.3(API Level 18)開始引入Bluetooth Low Energy(BLE,低功耗藍(lán)牙)的核心功能并提供了相應(yīng)的 API, 應(yīng)用程序通過(guò)這些 API 掃描藍(lán)牙設(shè)備、查詢 services、讀寫設(shè)備的 characteristics(屬性特征)等操作。

[[432207]]

前言

有老鐵們私信,要講解下藍(lán)牙開發(fā),那么今天來(lái)了;

Android 4.3(API Level 18)開始引入Bluetooth Low Energy(BLE,低功耗藍(lán)牙)的核心功能并提供了相應(yīng)的 API, 應(yīng)用程序通過(guò)這些 API 掃描藍(lán)牙設(shè)備、查詢 services、讀寫設(shè)備的 characteristics(屬性特征)等操作。

BLE低功耗藍(lán)牙,主要特點(diǎn)是快速搜索,快速連接,超低功耗保持連接和數(shù)據(jù)傳輸;

一、BLE開發(fā)流程

1、申請(qǐng)權(quán)限

安卓手機(jī)涉及藍(lán)牙權(quán)限問(wèn)題,藍(lán)牙開發(fā)需要在AndroidManifest.xml文件中添加權(quán)限聲明:

  1. <!-- 藍(lán)牙權(quán)限 --> 
  2. <uses-permission android:name="android.permission.BLUETOOTH" /> 
  3. <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> 
  4. 為適配安卓6.0以及以上版本需要添加一個(gè)模糊定位的權(quán)限 
  5.  <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> 
  6. 手機(jī)權(quán)限管理中允許此權(quán)限,否則會(huì)出現(xiàn)無(wú)法搜索到設(shè)備的情況; 

為適配安卓6.0以及以上版本需要添加一個(gè)模糊定位的權(quán)限

手機(jī)權(quán)限管理中允許此權(quán)限,否則會(huì)出現(xiàn)無(wú)法搜索到設(shè)備的情況;

2、打開藍(lán)牙

在搜索設(shè)備之前需要詢問(wèn)打開手機(jī)藍(lán)牙:

  1. //獲取系統(tǒng)藍(lán)牙適配器管理類 
  2.     private BluetoothAdapter mBluetoothAdapter = BluetoothAdapter 
  3.             .getDefaultAdapter(); 
  4.     // 詢問(wèn)打開藍(lán)牙 
  5.     if (mBluetoothAdapter != null && !mBluetoothAdapter.isEnabled()) { 
  6.             Intent enableBtIntent = new Intent( 
  7.                     BluetoothAdapter.ACTION_REQUEST_ENABLE); 
  8.             startActivityForResult(enableBtIntent, 1); 
  9.     } 
  10.       // 申請(qǐng)打開藍(lán)牙請(qǐng)求的回調(diào) 
  11.     @Override 
  12.     protected void onActivityResult(int requestCode, int resultCode, Intent data) { 
  13.         // TODO Auto-generated method stub 
  14.         super.onActivityResult(requestCode, resultCode, data); 
  15.         if (requestCode == 1) { 
  16.             if (resultCode == RESULT_OK) { 
  17.                 Toast.makeText(this, "藍(lán)牙已經(jīng)開啟", Toast.LENGTH_SHORT).show(); 
  18.             } else if (resultCode == RESULT_CANCELED) { 
  19.                 Toast.makeText(this, "沒(méi)有藍(lán)牙權(quán)限", Toast.LENGTH_SHORT).show(); 
  20.                 finish(); 
  21.             } 
  22.         } 
  23.     } 

3、搜索設(shè)備

  1. mBluetoothAdapter.startLeScan(callback); 
  2. private LeScanCallback callback = new LeScanCallback() { 
  3.     @Override 
  4.     public void onLeScan(BluetoothDevice device, int arg1, byte[] arg2) { 
  5.         //device為掃描到的BLE設(shè)備 
  6.         if(device.getName() == "目標(biāo)設(shè)備名稱"){ 
  7.             //獲取目標(biāo)設(shè)備 
  8.             targetDevice = device; 
  9.         } 
  10.     } 
  11. }; 

4、連接設(shè)備

通過(guò)掃描BLE設(shè)備,根據(jù)設(shè)備名稱區(qū)分出目標(biāo)設(shè)備targetDevice,下一步實(shí)現(xiàn)與目標(biāo)設(shè)備的連接,在連接設(shè)備之前要停止搜索藍(lán)牙;

mBluetoothAdapter.stopLeScan(callback);

停止搜索一般需要一定的時(shí)間來(lái)完成,最好調(diào)用停止搜索函數(shù)之后加以100ms的延時(shí),保證系統(tǒng)能夠完全停止搜索藍(lán)牙設(shè)備。停止搜索之后啟動(dòng)連接過(guò)程;

BLE藍(lán)牙的連接方法相對(duì)簡(jiǎn)單只需調(diào)用connectGatt方法;

  1. mBluetoothAdapter.startLeScan(callback); 
  2. private LeScanCallback callback = new LeScanCallback() { 
  3.     @Override 
  4.     public void onLeScan(BluetoothDevice device, int arg1, byte[] arg2) { 
  5.         //device為掃描到的BLE設(shè)備 
  6.         if(device.getName() == "目標(biāo)設(shè)備名稱"){ 
  7.             //獲取目標(biāo)設(shè)備 
  8.             targetDevice = device; 
  9.         } 
  10.     } 
  11. }; 

參數(shù)說(shuō)明

返回值 BluetoothGatt: BLE藍(lán)牙連接管理類,主要負(fù)責(zé)與設(shè)備進(jìn)行通信;

boolean autoConnect:建議置為false,能夠提升連接速度;

BluetoothGattCallback callback 連接回調(diào),重要參數(shù),BLE通信的核心部分;

5、設(shè)備通信

與設(shè)備建立連接之后與設(shè)備通信,整個(gè)通信過(guò)程都是在BluetoothGattCallback的異步回調(diào)函數(shù)中完成;

BluetoothGattCallback中主要回調(diào)函數(shù)如下:

  1. private BluetoothGattCallback gattCallback = new BluetoothGattCallback() { 
  2.         @Override 
  3.         public void onConnectionStateChange(BluetoothGatt gatt, int status, 
  4.                 int newState) { 
  5.         } 
  6.         @Override 
  7.         public void onCharacteristicWrite(BluetoothGatt gatt, 
  8.                 BluetoothGattCharacteristic characteristic, int status) { 
  9.             super.onCharacteristicWrite(gatt, characteristic, status); 
  10.         } 
  11.         @Override 
  12.         public void onDescriptorWrite(BluetoothGatt gatt, 
  13.                 BluetoothGattDescriptor descriptor, int status) { 
  14.         }; 
  15.         @Override 
  16.         public void onServicesDiscovered(BluetoothGatt gatt, int status) { 
  17.         } 
  18.         @Override 
  19.         public void onCharacteristicChanged(BluetoothGatt gatt, 
  20.                 BluetoothGattCharacteristic characteristic) { 
  21.         } 
  22.     }; 

上述幾個(gè)回調(diào)函數(shù)是BLE開發(fā)中不可缺少的;

6、等待設(shè)備連接成功

當(dāng)調(diào)用targetdDevice.connectGatt(context, false, gattCallback)后系統(tǒng)會(huì)主動(dòng)發(fā)起與BLE藍(lán)牙設(shè)備的連接,若成功連接到設(shè)備將回調(diào)onConnectionStateChange方法,其處理過(guò)程如下:

  1. @Override 
  2. public void onConnectionStateChange(BluetoothGatt gatt, int status, 
  3.                 int newState) { 
  4.             if (newState == BluetoothGatt.STATE_CONNECTED) { 
  5.                 Log.e(TAG, "設(shè)備連接上 開始掃描服務(wù)"); 
  6.                 // 開始掃描服務(wù),安卓藍(lán)牙開發(fā)重要步驟之一 
  7.                 mBluetoothGatt.discoverServices(); 
  8.             } 
  9.             if (newState == BluetoothGatt.STATE_DISCONNECTED) { 
  10.                 // 連接斷開 
  11.                 /*連接斷開后的相應(yīng)處理*/       
  12.             } 
  13. }; 

判斷newState == BluetoothGatt.STATE_CONNECTED表明此時(shí)已經(jīng)成功連接到設(shè)備;

7、開啟掃描服務(wù)

mBluetoothGatt.discoverServices();

掃描BLE設(shè)備服務(wù)是安卓系統(tǒng)中關(guān)于BLE藍(lán)牙開發(fā)的重要一步,一般在設(shè)備連接成功后調(diào)用,掃描到設(shè)備服務(wù)后回調(diào)onServicesDiscovered()函數(shù),函數(shù)原型如下:

  1. @Override 
  2. public void onServicesDiscovered(BluetoothGatt gatt, int status) { 
  3.     private List<BluetoothGattService> servicesList; 
  4.     //獲取服務(wù)列表 
  5.     servicesList = mBluetoothGatt.getServices(); 
  • BLE藍(lán)牙協(xié)議下數(shù)據(jù)的通信方式采用BluetoothGattService、BluetoothGattCharacteristic和BluetoothGattDescriptor三個(gè)主要的類實(shí)現(xiàn)通信;
  • BluetoothGattService 簡(jiǎn)稱服務(wù),是構(gòu)成BLE設(shè)備協(xié)議棧的組成單位,一個(gè)藍(lán)牙設(shè)備協(xié)議棧一般由一個(gè)或者多個(gè)BluetoothGattService組成;
  • BluetoothGattCharacteristic 簡(jiǎn)稱特征,一個(gè)服務(wù)包含一個(gè)或者多個(gè)特征,特征作為數(shù)據(jù)的基本單元;
  • 一個(gè)BluetoothGattCharacteristic特征包含一個(gè)數(shù)據(jù)值和附加的關(guān)于特征的描述
  • BluetoothGattDescriptor:用于描述特征的類,其同樣包含一個(gè)value值;

8、獲取負(fù)責(zé)通信的BluetoothGattCharacteristic

BLE藍(lán)牙開發(fā)主要有負(fù)責(zé)通信的BluetoothGattService完成的。當(dāng)且稱為通信服務(wù)。通信服務(wù)通過(guò)硬件工程師提供的UUID獲取。獲取方式如下:

  • BluetoothGattService service = mBluetoothGatt.getService(UUID.fromString("藍(lán)牙模塊提供的負(fù)責(zé)通信UUID字符串"));
  • 通信服務(wù)中包含負(fù)責(zé)讀寫的BluetoothGattCharacteristic,且分別稱為notifyCharacteristic和writeCharacteristic。其中notifyCharacteristic負(fù)責(zé)開啟監(jiān)聽,也就是啟動(dòng)收數(shù)據(jù)的通道,writeCharacteristic負(fù)責(zé)寫入數(shù)據(jù);

具體操作方式如下:

  1. BluetoothGattService service = mBluetoothGatt.getService(UUID.fromString("藍(lán)牙模塊提供的負(fù)責(zé)通信服務(wù)UUID字符串")); 
  2.    // 例如形式如:49535343-fe7d-4ae5-8fa9-9fafd205e455 
  3.   notifyCharacteristic = service.getCharacteristic(UUID.fromString("notify uuid")); 
  4.   writeCharacteristic =  service.getCharacteristic(UUID.fromString("write uuid")); 

9、開啟監(jiān)聽

開啟監(jiān)聽,即建立與設(shè)備的通信的首發(fā)數(shù)據(jù)通道,BLE開發(fā)中只有當(dāng)上位機(jī)成功開啟監(jiān)聽后才能與下位機(jī)收發(fā)數(shù)據(jù)。開啟監(jiān)聽的方式如下:

  1. mBluetoothGatt.setCharacteristicNotification(notifyCharacteristic, true
  2. BluetoothGattDescriptor descriptor = characteristic 
  3.                             .getDescriptor(UUID 
  4.                                     .fromString 
  5. ("00002902-0000-1000-8000-00805f9b34fb")); 
  6. descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); 

若開啟監(jiān)聽成功則會(huì)回調(diào)BluetoothGattCallback中的onDescriptorWrite()方法,處理方式如下:

  1. @Override 
  2. public void onDescriptorWrite(BluetoothGatt gatt, 
  3.                 BluetoothGattDescriptor descriptor, int status) { 
  4.         if (status == BluetoothGatt.GATT_SUCCESS) { 
  5.             //開啟監(jiān)聽成功,可以像設(shè)備寫入命令了 
  6.             Log.e(TAG, "開啟監(jiān)聽成功"); 
  7.         } 
  8. }; 

10、寫入數(shù)據(jù)

監(jiān)聽成功后通過(guò)向 writeCharacteristic寫入數(shù)據(jù)實(shí)現(xiàn)與下位機(jī)的通信。寫入方式如下:

  1. //value為上位機(jī)向下位機(jī)發(fā)送的指令 
  2. writeCharacteristic.setValue(value); 
  3. mBluetoothGatt.writeCharacteristic(writeCharacteristic) 

其中:value一般為Hex格式指令,其內(nèi)容由設(shè)備通信的藍(lán)牙通信協(xié)議規(guī)定;

11、接收數(shù)據(jù)

若寫入指令成功則回調(diào)BluetoothGattCallback中的onCharacteristicWrite()方法,說(shuō)明將數(shù)據(jù)已經(jīng)發(fā)送給下位機(jī);

  1. @Override 
  2. public void onCharacteristicWrite(BluetoothGatt gatt, 
  3.             BluetoothGattCharacteristic characteristic, int status) { 
  4.             if (status == BluetoothGatt.GATT_SUCCESS) { 
  5.                 Log.e(TAG, "發(fā)送成功"); 
  6.             }    
  7.             super.onCharacteristicWrite(gatt, characteristic, status); 

若發(fā)送的數(shù)據(jù)符合通信協(xié)議,則下位機(jī)會(huì)向上位機(jī)回復(fù)相應(yīng)的數(shù)據(jù)。發(fā)送的數(shù)據(jù)通過(guò)回調(diào)onCharacteristicChanged()方法獲取,其處理方式如下:

  1. @Override 
  2. public void onCharacteristicChanged(BluetoothGatt gatt, 
  3.                 BluetoothGattCharacteristic characteristic) { 
  4.             // value為設(shè)備發(fā)送的數(shù)據(jù),根據(jù)數(shù)據(jù)協(xié)議進(jìn)行解析 
  5.             byte[] value = characteristic.getValue(); 

通過(guò)向下位機(jī)發(fā)送指令獲取下位機(jī)的回復(fù)數(shù)據(jù),即可完成與設(shè)備的通信過(guò)程;

12、斷開連接

當(dāng)與設(shè)備完成通信之后之后一定要斷開與設(shè)備的連接。調(diào)用以下方法斷開與設(shè)備的連接:

  1. mBluetoothGatt.disconnect(); 
  2.  
  3. mBluetoothGatt.close(); 

二、藍(lán)牙操作的注意事項(xiàng)

  • 藍(lán)牙的寫入操作, 讀取操作必須序列化進(jìn)行. 寫入數(shù)據(jù)和讀取數(shù)據(jù)是不能同時(shí)進(jìn)行的, 如果調(diào)用了寫入數(shù)據(jù)的方法, 馬上調(diào)用又調(diào)用寫入數(shù)據(jù)或者讀取數(shù)據(jù)的方法,第二次調(diào)用的方法會(huì)立即返回 false, 代表當(dāng)前無(wú)法進(jìn)行操作;
  • Android 連接外圍設(shè)備的數(shù)量有限,當(dāng)不需要連接藍(lán)牙設(shè)備的時(shí)候,必須調(diào)用 BluetoothGatt#close 方法釋放資源;
  • 藍(lán)牙 API 連接藍(lán)牙設(shè)備的超時(shí)時(shí)間大概在 20s 左右,具體時(shí)間看系統(tǒng)實(shí)現(xiàn)。有時(shí)候某些設(shè)備進(jìn)行藍(lán)牙連接的時(shí)間會(huì)很長(zhǎng),大概十多秒。如果自己手動(dòng)設(shè)置了連接超時(shí)時(shí)間在某些設(shè)備上可能會(huì)導(dǎo)致接下來(lái)幾次的連接嘗試都會(huì)在 BluetoothGattCallback#onConnectionStateChange 返回 state == 133;
  • 所有的藍(lán)牙操作使用 Handler 固定在一條線程操作,這樣能省去很多因?yàn)榫€程不同步導(dǎo)致的麻煩;

總結(jié)

 

藍(lán)牙開發(fā)中有很多問(wèn)題,要靜下心分析問(wèn)題,肯定可以解決的,一起加油;

 

責(zé)任編輯:武曉燕 來(lái)源: Android開發(fā)編程
相關(guān)推薦

2022-10-26 07:39:36

MVCC數(shù)據(jù)庫(kù)RR

2022-12-19 08:14:30

注解開發(fā)配置

2021-05-20 06:57:16

RabbitMQ開源消息

2015-09-22 11:04:24

藍(lán)牙4.0開發(fā)

2021-07-14 10:08:30

責(zé)任鏈模式加工鏈

2021-07-10 09:02:42

編程語(yǔ)言 TypeScript

2021-10-28 19:15:02

IPUARM

2020-10-09 08:15:11

JsBridge

2022-01-25 16:54:14

BLE操作系統(tǒng)鴻蒙

2023-05-12 08:19:12

Netty程序框架

2021-06-30 00:20:12

Hangfire.NET平臺(tái)

2021-07-28 10:02:54

建造者模式代碼

2021-12-30 09:38:51

DDoS攻擊防范

2022-06-08 00:10:33

數(shù)據(jù)治理框架

2021-07-14 08:24:23

TCPIP 通信協(xié)議

2021-08-11 07:02:21

npm包管理器工具

2021-08-02 06:34:55

Redis刪除策略開源

2021-11-08 08:42:44

CentOS Supervisor運(yùn)維

2021-11-24 08:51:32

Node.js監(jiān)聽函數(shù)

2022-07-31 20:00:59

云原生云計(jì)算
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)