【Android應(yīng)用開發(fā)】Android 藍(lán)牙低功耗 (BLE) ( 第一篇 . 概述 . 藍(lán)牙低功耗文檔 翻譯)

      網(wǎng)友投稿 1531 2025-03-31

      轉(zhuǎn)載請注明出處 :?http://blog.csdn.net/shulianghan/article/details/50515359

      參考 :

      -- 官方文檔 : https://developer.android.com/guide/topics/connectivity/bluetooth-le.html;

      1. 概述

      BLE 概述 :

      -- 版本支持 :?Android 4.3 (API Level 18) 內(nèi)置框架引入了 藍(lán)牙低功耗方案 (Bluetooth Low Energy, BLE) 支持;

      -- 角色支持 : Android 手機(jī)只能作為 主設(shè)備 (central role), 開發(fā)者開發(fā)的 APP 可以使用其提供的 API 接口, 用于 發(fā)現(xiàn)設(shè)備, 遍歷服務(wù) (services), ?讀寫服務(wù)中的特性 (characteristics).

      -- 傳統(tǒng)藍(lán)牙對比 : 與傳統(tǒng)的藍(lán)牙對比, 藍(lán)牙低功耗方案 (Bluetooth Low Energy) 是出于更低的電量消耗考慮而設(shè)計(jì)的. 這可以使 Android 應(yīng)用可以與 BLE 設(shè)備進(jìn)行交流, 這些設(shè)備需要很低的電量, 如 近距離傳感器, 心率測量設(shè)備, 健康設(shè)備 等等.

      2. 關(guān)鍵術(shù)語 和 概念

      (1) Generic Attribute Profile (GATT) 通用屬性規(guī)范

      Generic Attribute Profile (GATT) 通用屬性規(guī)范?:

      -- GATT 作用 : GATT 規(guī)范是一個(gè)針對 在 BLE 連接上的, 發(fā)送 和 接收 少量數(shù)據(jù)的一個(gè)規(guī)范, 所有的現(xiàn)有的低功耗應(yīng)用的規(guī)范都是基于這個(gè) GATT 規(guī)范制定的.

      -- 制定者 : 藍(lán)牙技術(shù)聯(lián)盟 (Bluetooth SIG) 為低功耗設(shè)備定義了許多規(guī)范, 一個(gè) 規(guī)范 (Profile) 就是 設(shè)備如何在特定的應(yīng)用中工作的詳述.

      -- 設(shè)備規(guī)范對應(yīng)關(guān)系 : 此外, 一個(gè)設(shè)備可以實(shí)現(xiàn)多個(gè)規(guī)范, 如 : 一個(gè)設(shè)備可以包含一個(gè)心率檢測器, 和 電量檢測器.

      (2) Attribute Protocol?(ATT) 屬性協(xié)議

      Attribute Protocol (ATT) 屬性協(xié)議 :

      -- ATT 與 GATT 關(guān)系 : GATT 規(guī)范是建立在 ATT 的上一層的, 這套改改通常被稱為 GATT/ATT.

      -- ATT 作用 : ATT 被用于優(yōu)化 BLE 設(shè)備的運(yùn)行, 為了這個(gè)目的, ATT (屬性協(xié)議) 使用盡可能少的字節(jié).

      -- ATT 唯一標(biāo)識(shí) : ATT 中的每個(gè)屬性都被 一個(gè) UUID (Universally Unique Identifier) 獨(dú)一無二的進(jìn)行標(biāo)識(shí), UUID 是一個(gè) 128 比特的標(biāo)準(zhǔn)的字符串 ID, 用于信息的唯一標(biāo)識(shí).

      -- ATT 屬性 : ATT 中定義的屬性就是 Charicteristics (特性) 和 Services (服務(wù));

      (3) Characteristic 特性

      Characteristic 特性 :

      -- Characteristic 概念 : 一個(gè) Characteristic 特性包含了一個(gè)值 和 多個(gè) Descriptor (描述符) 用于描述這個(gè)特性的值.

      -- 本質(zhì) : 一個(gè)特性可以被認(rèn)為是一個(gè)類型, 類似于一個(gè)類.

      (4) Descriptor 描述符

      Descriptor 描述符 :

      -- 作用 : 描述符 被定義為一些屬性, 這些屬性用于描述 Characteristic (特性) 的值.

      -- 示例 : 例如, 一個(gè) 描述符 可以說明一個(gè) 可讀的描述, 一個(gè) 特性值的可接受范圍, 或者 一個(gè)特性值的測量單元.

      (5) Service 服務(wù)

      Service 服務(wù) :

      -- 服務(wù)本質(zhì) : 服務(wù)是 Characteristic (特性) 的集合.

      -- 示例 : 如, 你可以有一個(gè) 名稱為 "Heart Rate?Monitor (心率監(jiān)控)" 的服務(wù), 包含了特性 "Heart Rate Measurement (心率測量)".

      -- 參考資料 : 你可以在 bluetooth.org 官網(wǎng)查詢到一個(gè)基于 GATT 服務(wù) 和 規(guī)范的列表.

      3. 角色 和 職責(zé)

      (1) 四種角色

      Android 設(shè)備 與 BLE 設(shè)備互動(dòng)時(shí), 設(shè)備的角色 和 職責(zé) :

      -- 中心設(shè)備 和 外圍設(shè)備 : 這個(gè)角色體系適用于 BLE 連接. 中心設(shè)備角色 可以掃描, 查找廣播. 外圍設(shè)備角色 發(fā)送廣播.

      -- GATT 服務(wù)器 和 GATT 客戶端 : 這個(gè)決定了兩個(gè)設(shè)備之間, 一旦建議連接后, 如何進(jìn)行互相通信.

      (2) 中心設(shè)備 和 外圍設(shè)備

      BLE 連接需要兩種設(shè)備都存在 : 為了理解其中的區(qū)別, 想象一下 你有一個(gè) Android 設(shè)備 和 一個(gè)激活的 智能腕表?藍(lán)牙設(shè)備. 手機(jī)支持作為 中心設(shè)備 角色, 智能腕表 藍(lán)牙設(shè)備支持作為外圍設(shè)備角色, 為了建立 BLE 連接, 只有外圍設(shè)備 或者 只有 中心設(shè)備 都不能建立 BLE?連接.

      (3) GATT 服務(wù)器 和 GATT 客戶端

      GATT 服務(wù)器 和 GATT 客戶端 簡介 :

      -- GATT 服務(wù)器 和 GATT 客戶端 角色不是固定的 : 一旦手機(jī) 和 智能腕表 設(shè)備建立了 BLE 連接, 它們開始互相交換 GATT 元數(shù)據(jù). 根據(jù)它們之間傳輸?shù)臄?shù)據(jù)類型, 其中的一個(gè)會(huì)扮演 GATT 服務(wù)器的角色.

      -- 角色改變示例 : 如果 智能腕表 設(shè)備想要向手機(jī)報(bào)告?zhèn)鞲衅鲾?shù)據(jù), 那么智能腕表必須當(dāng)做 GATT 服務(wù)器. 如果智能腕表 想要從手機(jī)上接受更新數(shù)據(jù), 那么 Android 手機(jī)就是 GATT 服務(wù)器.

      -- 手機(jī) 和 設(shè)備 都可以作為 GATT 服務(wù)器 和 客戶端 : 在本文檔中使用的示例代碼, 在 Android 設(shè)備上運(yùn)行的 Android APP 就是 GATT 客戶端, BLE 外圍設(shè)備?就是 GATT 服務(wù)器. Android APP 從 GATT 服務(wù)器上獲取數(shù)據(jù), 服務(wù)器的 BLE "heart rate monitor (心率監(jiān)測)" 支持 "Heart Rate Profile (心率規(guī)范 - 一種 BLE 藍(lán)牙標(biāo)準(zhǔn)規(guī)范)". Android APP 也可以作為 GATT 服務(wù)器;

      4. BLE 權(quán)限

      (1) 藍(lán)牙權(quán)限簡介

      Android 藍(lán)牙權(quán)限簡介 :

      -- 權(quán)限作用 : 為了在應(yīng)用中使用藍(lán)牙功能, 必須在 AndroidManifest.xml?中 聲明藍(lán)牙權(quán)限. 所有的藍(lán)牙通信操作都需要 藍(lán)牙權(quán)限 來允許執(zhí)行, 例如 搜索藍(lán)牙, 藍(lán)牙連接, 數(shù)據(jù)交互等操作.

      -- 搜索設(shè)置藍(lán)牙權(quán)限 : 如果 APP 要發(fā)起設(shè)備搜索 或者 管理 藍(lán)牙設(shè)置, 需要 提前聲明 BLUETOOTH_ADMIN 權(quán)限.

      -- 注意 : 使用 BLUETOOTH_ADMIN 權(quán)限的前提是 必須聲明 BLUETOOTH 權(quán)限.

      (2) 藍(lán)牙權(quán)限簡介

      藍(lán)牙權(quán)限示例 :

      -- AndroidManifest.xml 聲明藍(lán)牙權(quán)限示例 :

      (3) 動(dòng)態(tài)控制 BLE 功能是否使用

      //使用下面的函數(shù)決定 設(shè)備上的 BLE 功能 是否可用

      //此時(shí)你可以選擇性的關(guān)閉 BLE 相關(guān)的功能

      if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {

      Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_SHORT).show();

      finish();

      }

      5. 創(chuàng)建 BLE

      (1) 創(chuàng)建 BLE 簡介

      創(chuàng)建 BLE 簡介 :

      -- 驗(yàn)證 BLE 功能 : 在應(yīng)用可以通過 BLE 交互之前, 你需要驗(yàn)證設(shè)備是否支持 BLE 功能, 如果支持, 確定它是可以使用的.

      -- 注意 : 這個(gè)檢查只有在 下面的配置 設(shè)置為 false 時(shí)才是必須的;

      -- 支持 BLE 打開藍(lán)牙 : 如果 BLE 支持 BLE 功能, 但是設(shè)備的藍(lán)牙是關(guān)閉的, 你可以在應(yīng)用中請求打開設(shè)備的藍(lán)牙模塊.

      -- 步驟總結(jié) : 創(chuàng)建 BLE 藍(lán)牙的過程分成兩個(gè)步驟, 1. 獲取 BluetoothAdapter, 2. 打開 設(shè)備的藍(lán)牙模塊.

      (2) 獲取 BluetoothAdapter (藍(lán)牙適配器)

      獲取 BluetoothAdapter 藍(lán)牙適配器 :

      -- BluetoothAdapter 類作用 : 所有的藍(lán)牙活動(dòng)都需要 BluetoothAdapter, BluetoothAdapter 代表了設(shè)備本身的藍(lán)牙適配器 (藍(lán)牙無線設(shè)備). 整個(gè)系統(tǒng)中只有一個(gè) 藍(lán)牙適配器, 應(yīng)用可以使用 BluetoothAdapter 對象與 藍(lán)牙適配器硬件進(jìn)行交互.

      -- 獲取 BluetoothAdapter 代碼示例 :

      // 初始化藍(lán)牙適配器

      final BluetoothManager bluetoothManager =

      (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);

      mBluetoothAdapter = bluetoothManager.getAdapter();

      -- 注意 : 這個(gè)方法使用了 getSystemService() 方法, 返回了一個(gè) BluetoothManager 實(shí)例對象, 從 BluetoothManager 實(shí)例對象中可以獲取 BluetoothAdapter 對象;

      (3) 打開藍(lán)牙功能

      打開藍(lán)牙 :

      -- 檢查是否可用 : 為了保證 藍(lán)牙功能是打開的, 調(diào)用 BluetoothAdapter 的 isEnable() 方法, 檢查藍(lán)牙在當(dāng)前是否可用. 如果返回 false, 說明當(dāng)前藍(lán)牙不可用.

      -- 示例代碼 :

      private BluetoothAdapter mBluetoothAdapter;

      ...

      // 確認(rèn)當(dāng)前設(shè)備的藍(lán)牙是否可用,

      // 如果不可用, 彈出一個(gè)對話框, 請求打開設(shè)備的藍(lán)牙模塊

      if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {

      Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);

      startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);

      }

      6. 查找 BLE 設(shè)備

      (1) 查找所有的?BLE 設(shè)備

      查找 BLE 設(shè)備 :

      -- 查找方法參數(shù) : 為了搜索到?BLE 設(shè)備, 調(diào)用 BluetoothAdapter 的 startLeScan() 方法, 該方法需要一個(gè) BluetoothAdapter.LeScanCallback 類型的參數(shù). 你必須實(shí)現(xiàn)這個(gè) LeScanCallback 接口, 因?yàn)?BLE 藍(lán)牙設(shè)備掃描結(jié)果在這個(gè)接口中返回.

      -- 查找策略 : 藍(lán)牙搜索是非常耗電的, 你需要遵守以下的 中斷策略 和 不循環(huán)策略.

      -- 中斷策略 : 只要一發(fā)現(xiàn)藍(lán)牙設(shè)備, 馬上中斷掃描.

      -- 不循環(huán)策略 : 不要循環(huán)掃描, 設(shè)置一個(gè)掃描的最大時(shí)間限制. 一個(gè)設(shè)備在之前可用, 繼續(xù)掃描可能會(huì)使設(shè)備不可用, 此外繼續(xù)掃描會(huì)持續(xù)浪費(fèi)電池電量.

      -- 源碼示例 :

      /**

      * 搜索 和 展示 可用的藍(lán)牙設(shè)備 的 Activity 界面

      */

      public class DeviceScanActivity extends ListActivity {

      private BluetoothAdapter mBluetoothAdapter;

      private boolean mScanning;

      private Handler mHandler;

      // 10 秒后停止搜索

      private static final long SCAN_PERIOD = 10000;

      ...

      private void scanLeDevice(final boolean enable) {

      if (enable) {

      // 在一個(gè)預(yù)先定義的時(shí)間段后停止掃描.

      mHandler.postDelayed(new Runnable() {

      @Override

      public void run() {

      mScanning = false;

      //開始掃描

      mBluetoothAdapter.stopLeScan(mLeScanCallback);

      }

      }, SCAN_PERIOD);

      mScanning = true;

      mBluetoothAdapter.startLeScan(mLeScanCallback);

      } else {

      mScanning = false;

      mBluetoothAdapter.stopLeScan(mLeScanCallback);

      }

      ...

      }

      ...

      }

      (2) 查找特定?BLE 設(shè)備

      查找特定 BLE 設(shè)備 :

      -- 方法調(diào)用 : 查找特定類型的外圍設(shè)備, 可以調(diào)用下面的方法, 這個(gè)方法需要提供一個(gè) UUID 對象數(shù)組, 這個(gè) UUID 數(shù)組是 APP 支持的 GATT 服務(wù)的特殊標(biāo)識(shí).

      -- 示例 :

      startLeScan(UUID[], BluetoothAdapter.LeScanCallback)

      (3) BluetoothAdapter.LeScanCallback 回調(diào)接口

      -- 接口作用 : BluetoothAdapter.LeScanCallback 實(shí)現(xiàn)類, 在這個(gè)實(shí)現(xiàn)類的接口中返回 BLE 設(shè)備掃描結(jié)果;

      -- 源碼示例 :

      private LeDeviceListAdapter mLeDeviceListAdapter;

      ...

      // 設(shè)備掃描回調(diào)接口

      private BluetoothAdapter.LeScanCallback mLeScanCallback =

      new BluetoothAdapter.LeScanCallback() {

      @Override

      public void onLeScan(final BluetoothDevice device, int rssi,

      byte[] scanRecord) {

      runOnUiThread(new Runnable() {

      @Override

      public void run() {

      mLeDeviceListAdapter.addDevice(device);

      mLeDeviceListAdapter.notifyDataSetChanged();

      }

      });

      }

      };

      (4) 設(shè)備掃描類型

      設(shè)備掃描類型 : 藍(lán)牙設(shè)備掃描 在同一個(gè)時(shí)間掃描時(shí), 只能掃描 BLE 設(shè)備 或者 SPP 設(shè)備中的一種, 不能同時(shí)掃描兩種設(shè)備.

      7. 連接到 GATT 服務(wù)

      (1) 連接指定 BluetoothDevice 藍(lán)牙設(shè)備

      連接指定設(shè)備 :

      -- 連接到 GATT 服務(wù) : 與 BLE 設(shè)備交互的第一步是 連接到 BLE 設(shè)備中的 GATT 服務(wù).

      -- 實(shí)現(xiàn)方法 : 調(diào)用 BluetoothDevice 的 connectGatt() 方法可以連接到 BLE 設(shè)備的 GATT 服務(wù).

      -- 參數(shù)解析 : connectGatt() 方法需要三個(gè)參數(shù), 參數(shù)一 Context 上下文對象, 參數(shù)二 boolean autoConnect 是否自動(dòng)連接掃描到的藍(lán)牙設(shè)備, 參數(shù)三 BluetoothGattCallback 接口實(shí)現(xiàn)類.

      -- 用法示例 :

      mBluetoothGatt = device.connectGatt(this, false, mGattCallback);

      -- 獲取 BluetoothGatt 對象 : 調(diào)用 connectGatt() 方法可以連接到 BLE 設(shè)備上的 GATT 服務(wù), 返回一個(gè) BluetoothGatt 實(shí)例對象, 你可以使用這個(gè)對象去 管理 GATT 客戶端操作.

      -- GATT 客戶端操作 : Android APP 可以調(diào)用 GATT Client (客戶端). BluetoothGattCallback 可以用于傳遞結(jié)果到 GATT 客戶端, 如 連接狀態(tài) 和 更進(jìn)一步的 GATT Client 操作.

      (2) GATT 數(shù)據(jù)交互示例

      BLE 藍(lán)牙數(shù)據(jù)交互 :

      -- 界面 : 在下面的示例中, BLE 應(yīng)用提供了一個(gè) Activity 界面, 該 Activity 界面用于 連接, 展示數(shù)據(jù), 展示 GATT 服務(wù) 和 設(shè)備支持的特性.

      -- BLE 藍(lán)牙服務(wù)類 : 基于用戶的輸入, 這個(gè) Activity 界面可以與一個(gè) BluetoothLeService 的服務(wù)進(jìn)行交流, 該交流的本質(zhì)就是 BLE 設(shè)備的 GATT 服務(wù) 與 Android 的 BLE API 進(jìn)行交流.

      -- BLE 藍(lán)牙服務(wù)類 示例代碼 :

      // BLE 設(shè)備可以通過該服務(wù) 與 Android 的 BLE API 進(jìn)行互動(dòng)

      public class BluetoothLeService extends Service {

      private final static String TAG = BluetoothLeService.class.getSimpleName();

      private BluetoothManager mBluetoothManager;

      private BluetoothAdapter mBluetoothAdapter;

      private String mBluetoothDeviceAddress;

      private BluetoothGatt mBluetoothGatt;

      private int mConnectionState = STATE_DISCONNECTED;

      private static final int STATE_DISCONNECTED = 0;

      private static final int STATE_CONNECTING = 1;

      private static final int STATE_CONNECTED = 2;

      public final static String ACTION_GATT_CONNECTED =

      "com.example.bluetooth.le.ACTION_GATT_CONNECTED";

      public final static String ACTION_GATT_DISCONNECTED =

      "com.example.bluetooth.le.ACTION_GATT_DISCONNECTED";

      public final static String ACTION_GATT_SERVICES_DISCOVERED =

      "com.example.bluetooth.le.ACTION_GATT_SERVICES_DISCOVERED";

      public final static String ACTION_DATA_AVAILABLE =

      "com.example.bluetooth.le.ACTION_DATA_AVAILABLE";

      public final static String EXTRA_DATA =

      "com.example.bluetooth.le.EXTRA_DATA";

      public final static UUID UUID_HEART_RATE_MEASUREMENT =

      UUID.fromString(SampleGattAttributes.HEART_RATE_MEASUREMENT);

      // BLE API 中定義的不同的回調(diào)方法.

      private final BluetoothGattCallback mGattCallback =

      new BluetoothGattCallback() {

      @Override

      // BLE 設(shè)備的狀態(tài)改變 連接 斷開

      public void onConnectionStateChange(BluetoothGatt gatt, int status,

      int newState) {

      String intentAction;

      if (newState == BluetoothProfile.STATE_CONNECTED) {

      intentAction = ACTION_GATT_CONNECTED;

      mConnectionState = STATE_CONNECTED;

      broadcastUpdate(intentAction);

      Log.i(TAG, "連接到了 GATT 服務(wù).");

      Log.i(TAG, "嘗試搜索服務(wù):" +

      mBluetoothGatt.discoverServices());

      } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {

      intentAction = ACTION_GATT_DISCONNECTED;

      mConnectionState = STATE_DISCONNECTED;

      Log.i(TAG, "于 GATT 服務(wù)斷開連接.");

      broadcastUpdate(intentAction);

      }

      }

      @Override

      // BLE 設(shè)備中 新的 GATT 服務(wù)被發(fā)現(xiàn)

      public void onServicesDiscovered(BluetoothGatt gatt, int status) {

      if (status == BluetoothGatt.GATT_SUCCESS) {

      broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);

      } else {

      Log.w(TAG, "發(fā)現(xiàn) GATT 服務(wù) : " + status);

      }

      }

      @Override

      // 特性讀取操作返回的數(shù)據(jù)

      public void onCharacteristicRead(BluetoothGatt gatt,

      BluetoothGattCharacteristic characteristic,

      int status) {

      if (status == BluetoothGatt.GATT_SUCCESS) {

      broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);

      }

      }

      ...

      };

      ...

      }

      -- 廣播發(fā)送 : 當(dāng)一個(gè)特定的回調(diào)被觸發(fā), 它調(diào)用適當(dāng)?shù)?broadcastUpdate() 幫助方法, 將其當(dāng)做一個(gè) Action 操作傳遞出去.

      -- 注意藍(lán)牙心率?: 這部分的數(shù)據(jù)解析 與 藍(lán)牙心率測量 是一起被執(zhí)行的.

      -- 廣播發(fā)送 示例代碼 :

      private void broadcastUpdate(final String action) {

      final Intent intent = new Intent(action);

      sendBroadcast(intent);

      }

      private void broadcastUpdate(final String action,

      final BluetoothGattCharacteristic characteristic) {

      final Intent intent = new Intent(action);

      // This is special handling for the Heart Rate Measurement profile. Data

      // parsing is carried out as per profile specifications.

      // 心率監(jiān)測規(guī)范的特殊處理

      // 數(shù)據(jù)解析在每個(gè)規(guī)范中完成

      if (UUID_HEART_RATE_MEASUREMENT.equals(characteristic.getUuid())) {

      int flag = characteristic.getProperties();

      int format = -1;

      if ((flag & 0x01) != 0) {

      format = BluetoothGattCharacteristic.FORMAT_UINT16;

      Log.d(TAG, "心率格式 UINT16.");

      } else {

      format = BluetoothGattCharacteristic.FORMAT_UINT8;

      Log.d(TAG, "心率格式 UINT8.");

      }

      final int heartRate = characteristic.getIntValue(format, 1);

      Log.d(TAG, String.format("接收到心跳檢測 : %d", heartRate));

      intent.putExtra(EXTRA_DATA, String.valueOf(heartRate));

      } else {

      // 對于其它的規(guī)范, 寫出 HEX 十六進(jìn)制格式的數(shù)據(jù)

      final byte[] data = characteristic.getValue();

      if (data != null && data.length > 0) {

      final StringBuilder stringBuilder = new StringBuilder(data.length);

      for(byte byteChar : data)

      stringBuilder.append(String.format("%02X ", byteChar));

      intent.putExtra(EXTRA_DATA, new String(data) + "\n" +

      stringBuilder.toString());

      }

      }

      sendBroadcast(intent);

      }

      // 處理 Service 發(fā)起的的不同事件

      // ACTION_GATT_CONNECTED: 連接到 GATT 服務(wù).

      // ACTION_GATT_DISCONNECTED: 與 GATT 服務(wù)斷開.

      // ACTION_GATT_SERVICES_DISCOVERED: 發(fā)現(xiàn) GATT 服務(wù).

      // ACTION_DATA_AVAILABLE: 從 BLE 設(shè)備中接收數(shù)據(jù), 數(shù)據(jù)可以是 read 或者 Notification 操作的結(jié)果.

      private final BroadcastReceiver mGattUpdateReceiver = new BroadcastReceiver() {

      @Override

      public void onReceive(Context context, Intent intent) {

      final String action = intent.getAction();

      if (BluetoothLeService.ACTION_GATT_CONNECTED.equals(action)) {

      mConnected = true;

      updateConnectionState(R.string.connected);

      invalidateOptionsMenu();

      } else if (BluetoothLeService.ACTION_GATT_DISCONNECTED.equals(action)) {

      mConnected = false;

      updateConnectionState(R.string.disconnected);

      invalidateOptionsMenu();

      clearUI();

      } else if (BluetoothLeService.

      ACTION_GATT_SERVICES_DISCOVERED.equals(action)) {

      // 在用戶界面 顯示所有支持的服務(wù) 和 特性.

      displayGattServices(mBluetoothLeService.getSupportedGattServices());

      } else if (BluetoothLeService.ACTION_DATA_AVAILABLE.equals(action)) {

      displayData(intent.getStringExtra(BluetoothLeService.EXTRA_DATA));

      }

      }

      };

      8. 讀取 BLE 屬性

      讀寫屬性簡介 :

      -- 讀寫屬性前提 : Android 應(yīng)用連接到了 設(shè)備中的?GATT 服務(wù), 并且發(fā)現(xiàn)了 各種服務(wù) (特性集合), 可以讀寫其中的屬性.

      -- 讀寫屬性代碼示例?: 遍歷服務(wù) (特性集合) 和 特性, 將其展示在 UI 界面中.

      public class DeviceControlActivity extends Activity {

      ...

      // 示范如何通過其所支持的 GATT 遍歷 服務(wù) (Services) 和 特性 (Characteristics)

      // 在這個(gè)示例中, 我們將查詢出的數(shù)據(jù)填充到 UI 界面中的 ExpandableListView 中

      private void displayGattServices(List gattServices) {

      if (gattServices == null) return;

      String uuid = null;

      String unknownServiceString = getResources().

      getString(R.string.unknown_service);

      String unknownCharaString = getResources().

      getString(R.string.unknown_characteristic);

      ArrayList> gattServiceData =

      new ArrayList>();

      ArrayList>> gattCharacteristicData

      = new ArrayList>>();

      mGattCharacteristics =

      new ArrayList>();

      // 遍歷 GATT 服務(wù)

      for (BluetoothGattService gattService : gattServices) {

      HashMap currentServiceData =

      new HashMap();

      uuid = gattService.getUuid().toString();

      currentServiceData.put(

      LIST_NAME, SampleGattAttributes.

      lookup(uuid, unknownServiceString));

      currentServiceData.put(LIST_UUID, uuid);

      gattServiceData.add(currentServiceData);

      ArrayList> gattCharacteristicGroupData =

      new ArrayList>();

      // 獲取服務(wù)中的特性集合

      List gattCharacteristics =

      gattService.getCharacteristics();

      ArrayList charas =

      new ArrayList();

      // 循環(huán)遍歷特性集合

      for (BluetoothGattCharacteristic gattCharacteristic :

      gattCharacteristics) {

      charas.add(gattCharacteristic);

      HashMap currentCharaData =

      new HashMap();

      uuid = gattCharacteristic.getUuid().toString();

      currentCharaData.put(

      LIST_NAME, SampleGattAttributes.lookup(uuid,

      unknownCharaString));

      currentCharaData.put(LIST_UUID, uuid);

      gattCharacteristicGroupData.add(currentCharaData);

      【Android應(yīng)用開發(fā)】Android 藍(lán)牙低功耗 (BLE) ( 第一篇 . 概述 . 藍(lán)牙低功耗文檔 翻譯)

      }

      mGattCharacteristics.add(charas);

      gattCharacteristicData.add(gattCharacteristicGroupData);

      }

      ...

      }

      ...

      }

      9. 接收 GATT 通知

      -- 代碼示例 : 使用?setCharacteristicNotification() 方法為特性設(shè)置通知.

      private BluetoothGatt mBluetoothGatt;

      BluetoothGattCharacteristic characteristic;

      boolean enabled;

      ...

      // 設(shè)置是否監(jiān)聽某個(gè)特性改變

      mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);

      ...

      BluetoothGattDescriptor descriptor = characteristic.getDescriptor(

      UUID.fromString(SampleGattAttributes.CLIENT_CHARACTERISTIC_CONFIG));

      descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);

      mBluetoothGatt.writeDescriptor(descriptor);

      @Override

      // 特性通知

      public void onCharacteristicChanged(BluetoothGatt gatt,

      BluetoothGattCharacteristic characteristic) {

      broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);

      }

      10. 關(guān)閉 APP 中的 BLE 連接

      關(guān)閉 BLE 設(shè)備連接 :

      -- 關(guān)閉方法 : 一旦結(jié)束了 BLE 設(shè)備的使用, 調(diào)用 BluetoothGatt 的 close() 方法, 關(guān)閉 BLE 連接, 釋放相關(guān)的資源.

      -- 關(guān)閉示例 :

      public void close() {

      if (mBluetoothGatt == null) {

      return;

      }

      mBluetoothGatt.close();

      mBluetoothGatt = null;

      }

      轉(zhuǎn)載請注明出處?:?http://blog.csdn.net/shulianghan/article/details/50515359

      Android iOS 機(jī)器翻譯

      版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時(shí)內(nèi)刪除侵權(quán)內(nèi)容。

      版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時(shí)內(nèi)刪除侵權(quán)內(nèi)容。

      上一篇:商業(yè)鬼才教你 代理模式
      下一篇:升級ERP系統(tǒng)的真正原因
      相關(guān)文章
      亚洲av日韩综合一区久热| 亚洲午夜精品第一区二区8050| 中文字幕亚洲不卡在线亚瑟| 国产成人亚洲综合网站不卡| 亚洲综合在线成人一区| 国产gv天堂亚洲国产gv刚刚碰| 三上悠亚亚洲一区高清| 亚洲成网777777国产精品| 亚洲AV无码成H人在线观看 | 亚洲国产综合精品| 亚洲国产日产无码精品| 亚洲av成人一区二区三区| 亚洲一区精彩视频| 国产亚洲福利在线视频| 亚洲日韩一区二区三区| 天天综合亚洲色在线精品| 亚洲高清视频一视频二视频三| 亚洲综合色区在线观看| 亚洲精品狼友在线播放| 久久久久亚洲精品影视| 亚洲欧洲日本天天堂在线观看| 亚洲乱码无限2021芒果| 亚洲色大网站WWW永久网站| 国产精品亚洲av色欲三区| 亚洲精品国产高清嫩草影院| 狠狠综合久久综合88亚洲| 亚洲色精品aⅴ一区区三区| 亚洲AV人无码激艳猛片| 亚洲成a人片7777| 亚洲中文字幕无码av永久| 国产亚洲人成在线播放| 国产国拍亚洲精品福利 | 久久亚洲精品国产亚洲老地址 | 亚洲国产成人精品无码区二本 | 亚洲中文字幕无码一区二区三区| 久久青青草原亚洲AV无码麻豆| 亚洲最大的视频网站| 亚洲精品无码少妇30P| 亚洲男人天堂2020| 亚洲AV无码精品无码麻豆| 亚洲电影唐人社一区二区|