To build a better world !

          Android4.3 藍牙BLE初步


          Android4.3 藍牙BLE初步

          一、關鍵概念:

          Generic Attribute Profile (GATT)
          通過BLE連接,讀寫屬性類小數據的Profile通用規范?,F在所有的BLE應用Profile都是基于GATT的。
           
          Attribute Protocol (ATT)
          GATT是基于ATT Protocol的。ATT針對BLE設備做了專門的優化,具體就是在傳輸過程中使用盡量少的數據。每個屬性都有一個唯一的UUID,屬性將以characteristics and services的形式傳輸。
           
          Characteristic
          Characteristic可以理解為一個數據類型,它包括一個value和0至多個對次value的描述(Descriptor)。
           
          Descriptor
          對Characteristic的描述,例如范圍、計量單位等。
           
          Service
          Characteristic的集合。例如一個service叫做“Heart Rate Monitor”,它可能包含多個Characteristics,其中可能包含一個叫做“heart rate measurement"的Characteristic。
           

          二、角色和職責:

          Android設備與BLE設備交互有兩組角色:
           
          中心設備和外圍設備(Central vs. peripheral);
          GATT server vs. GATT client.
           
          Central vs. peripheral:
          中心設備和外圍設備的概念針對的是BLE連接本身。Central角色負責scan advertisement。而peripheral角色負責make advertisement。
           
          GATT server vs. GATT client:
          這兩種角色取決于BLE連接成功后,兩個設備間通信的方式。
           
          舉例說明:
          現有一個活動追蹤的BLE設備和一個支持BLE的Android設備。Android設備支持Central角色,而BLE設備支持peripheral角色。創建一個BLE連接需要這兩個角色都存在,都僅支持Central角色或者都僅支持peripheral角色則無法建立連接。
           
          當連接建立后,它們之間就需要傳輸GATT數據。誰做server,誰做client,則取決于具體數據傳輸的情況。例如,如果活動追蹤的BLE設備需要向Android設備傳輸sensor數據,則活動追蹤器自然成為了server端;而如果活動追蹤器需要從Android設備獲取更新信息,則Android設備作為server端可能更合適。
           
           

          三、權限及feature:

          和經典藍牙一樣,應用使用藍牙,需要聲明BLUETOOTH權限,如果需要掃描設備或者操作藍牙設置,則還需要BLUETOOTH_ADMIN權限:
          <uses-permission android:name="android.permission.BLUETOOTH"/>
          <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
           
          除了藍牙權限外,如果需要BLE feature則還需要聲明uses-feature:
          <uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>
           
          按時required為true時,則應用只能在支持BLE的Android設備上安裝運行;required為false時,Android設備均可正常安裝運行,需要在代碼運行時判斷設備是否支持BLE feature:
           
          // Use this check to determine whether BLE is supported on the device. Then
          // you can selectively disable BLE-related features.
          if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
              Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_SHORT).show();
              finish();
          }
           
           

          四、啟動藍牙:

          在使用藍牙BLE之前,需要確認Android設備是否支持BLE feature(required為false時),另外要需要確認藍牙是否打開。 
          如果發現不支持BLE,則不能使用BLE相關的功能。如果支持BLE,但是藍牙沒打開,則需要打開藍牙。
           
          打開藍牙的步驟:
           
          1、獲取BluetoothAdapter
           
          BluetoothAdapter是Android系統中所有藍牙操作都需要的,它對應本地Android設備的藍牙模塊,在整個系統中BluetoothAdapter是單例的。當你獲取到它的示例之后,就能進行相關的藍牙操作了。
           
          獲取BluetoothAdapter代碼示例如下:
          // Initializes Bluetooth adapter.
          final BluetoothManager bluetoothManager =
                  (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
          mBluetoothAdapter = bluetoothManager.getAdapter();
           
          注:這里通過getSystemService獲取BluetoothManager,再通過BluetoothManager獲取BluetoothAdapter。BluetoothManager在Android4.3以上支持(API level 18)。
           
          2、判斷是否支持藍牙,并打開藍牙
           
          獲取到BluetoothAdapter之后,還需要判斷是否支持藍牙,以及藍牙是否打開。
          如果沒打開,需要讓用戶打開藍牙:
          private BluetoothAdapter mBluetoothAdapter;
          ...
          // Ensures Bluetooth is available on the device and it is enabled. If not,
          // displays a dialog requesting user permission to enable Bluetooth.
          if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
              Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
              startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
          }
           
           

          五、搜索BLE設備:

          通過調用BluetoothAdapter的startLeScan()搜索BLE設備。調用此方法時需要傳入 BluetoothAdapter.LeScanCallback參數。
          因此你需要實現 BluetoothAdapter.LeScanCallback接口,BLE設備的搜索結果將通過這個callback返回。
           
          由于搜索需要盡量減少功耗,因此在實際使用時需要注意:
           
          1、當找到對應的設備后,立即停止掃描;
          2、不要循環搜索設備,為每次搜索設置適合的時間限制。避免設備不在可用范圍的時候持續不停掃描,消耗電量。
           
          搜索的示例代碼如下:
          /**
           * Activity for scanning and displaying available BLE devices.
           */
          public class DeviceScanActivity extends ListActivity {

              private BluetoothAdapter mBluetoothAdapter;
              private boolean mScanning;
              private Handler mHandler;

              // Stops scanning after 10 seconds.
              private static final long SCAN_PERIOD = 10000;
              ...
              private void scanLeDevice(final boolean enable) {
                  if (enable) {
                      // Stops scanning after a pre-defined scan period.
                      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);
                  }
                  ...
              }
          ...
          }
           
          如果你只需要搜索指定UUID的外設,你可以調用 startLeScan(UUID[], BluetoothAdapter.LeScanCallback)方法。
          其中UUID數組指定你的應用程序所支持的GATT Services的UUID。
           
           
          BluetoothAdapter.LeScanCallback的實現示例如下:
          private LeDeviceListAdapter mLeDeviceListAdapter;
          ...
          // Device scan callback.
          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();
                     }
                 });
             }
          };
           
          注意:搜索時,你只能搜索傳統藍牙設備或者BLE設備,兩者完全獨立,不可同時被搜索。
           
           

          六、連接GATT Server:

          兩個設備通過BLE通信,首先需要建立GATT連接。這里我們講的是Android設備作為client端,連接GATT Server。
          連接GATT Server,你需要調用BluetoothDevice的connectGatt()方法。此函數帶三個參數:Context、autoConnect(boolean)和BluetoothGattCallback對象。調用示例:
           
          mBluetoothGatt = device.connectGatt(this, false, mGattCallback);
           
          函數成功,返回BluetoothGatt對象,它是GATT profile的封裝。通過這個對象,我們就能進行GATT Client端的相關操作。BluetoothGattCallback用于傳遞一些連接狀態及結果。
           
          BluetoothGatt常規用到的幾個操作示例:
           
          connect() :連接遠程設備。
          discoverServices() : 搜索連接設備所支持的service。
          disconnect():斷開與遠程設備的GATT連接。
          close():關閉GATT Client端。
          readCharacteristic(characteristic) :讀取指定的characteristic。
          setCharacteristicNotification(characteristic, enabled) :設置當指定characteristic值變化時,發出通知。
          getServices() :獲取遠程設備所支持的services。
           
          等等。
           
          注:
          1、某些函數調用之間存在先后關系。例如首先需要connect上才能discoverServices。
          2、一些函數調用是異步的,需要得到的值不會立即返回,而會在BluetoothGattCallback的回調函數中返回。例如discoverServices與onServicesDiscovered回調,readCharacteristic與onCharacteristicRead回調,setCharacteristicNotification與onCharacteristicChanged回調等。
           
           

          posted on 2013-12-09 20:27 zh.weir 閱讀(60838) 評論(27)  編輯  收藏 所屬分類: Android應用秘技

          評論

          # re: Android4.3 藍牙BLE初步 2013-12-11 12:56 鵬達鎖業

          謝謝博主分享  回復  更多評論   

          # re: Android4.3 藍牙BLE初步 2013-12-23 20:20 yusy

          我現在有個功能是 手機APP 向 硬件發送指令!
          現在我使用上述方法鏈接上了設備 但是怎么去發送指令呢?
          BluetoothGatt bluetoothGatt = DeviceActivity.bluetoothGatt;
          BluetoothGattService service = bluetoothGatt.getService(
          UUID.fromString("xx"));
          BluetoothGattCharacteristic characteristic = service.getCharacteristic(UUID.fromString("oo"));
          characteristic.setValue(bytes);
          bluetoothGatt.writeCharacteristic(characteristic);
          這樣可以嗎? 如果可以 UUID 我要如何獲得,不能隨便找個UUID我試過了!
          求博主解答,十萬火急,真心感激不盡@鵬達鎖業

            回復  更多評論   

          # re: Android4.3 藍牙BLE初步[未登錄] 2013-12-23 21:15 zh.weir

          @yusy

          肯定不能隨便用個UUID啊。。。

          建議你先看看你的BLE外設支持的service是什么,如果是用的Bluetooth SIG標準的Profile,你可以在https://developer.bluetooth.org/gatt/profiles/Pages/ProfilesHome.aspx 這個網站找到對應的service和characteristic的UUID。如果不是標準的,你需要和對應的BLE外設方案商交流,以獲得相關資料。  回復  更多評論   

          # re: Android4.3 藍牙BLE初步[未登錄] 2014-02-04 23:20 Chris

          您好
          我現在正在嘗試要用Android手機讀取多個BLE設備的值
          看完您的文章後
          我發覺我原本的做法是Android爲Client端去向設備(Server)要資料
          不過當我連線好兩個設備時
          當其中一方開始傳送資料時
          另一方就會自動斷線
          不過單獨連線一個設備取資料都是沒問題的
          想請問是不是Client端沒辦法同時連線多個Server?
          感謝!  回復  更多評論   

          # re: Android4.3 藍牙BLE初步[未登錄] 2014-02-21 11:39 zh.weir

          @Chris

          應該是可以同時連接多個Server的。而且你也已經連上了。
          BLE最好不用于傳輸較大的數據,只是簡單的屬性讀寫。大數據傳輸過程中,引起連接斷開的情況經常發生,你可以抓下HCI log,看看連接斷開的原因是什么。  回復  更多評論   

          # re: Android4.3 藍牙BLE初步 2014-03-15 12:45 xchen

          android設備可以作為 Periphreal role么  回復  更多評論   

          # re: Android4.3 藍牙BLE初步[未登錄] 2014-03-17 11:17 zh.weir

          @xchen

          目前還不支持。硬件應該是支持的,軟件不支持。  回復  更多評論   

          # re: Android4.3 藍牙BLE初步 2014-03-29 10:37 xchen

          樓主 我用Android 設備作為中心設備 ,作為一個GATT Client端,去連接Ble設備。第一次是可以成功的,但是藍牙斷開后再次重連,發現連不上,從打印的狀態看是已綁定狀態。  回復  更多評論   

          # re: Android4.3 藍牙BLE初步[未登錄] 2014-04-02 14:58 zh.weir

          @xchen

          這個應該是你程序邏輯的問題了。應該在藍牙關閉時將ble設備斷開。你可以看看onDisconnect回調是否有被正常調起。另外,一些Android手機在這一塊確實存在系統穩定性的問題。  回復  更多評論   

          # re: Android4.3 藍牙BLE初步 2014-04-15 22:46 xchen

          @zh.weir
          一直沒解決 是協議層的問題 。謝謝了  回復  更多評論   

          # re: Android4.3 藍牙BLE初步 2014-04-30 16:00 cjolinss

          請問 yusy 后來搞定了嗎 我遇到同樣問題能連上,但是不知道該法什么命令@zh.weir  回復  更多評論   

          # re: Android4.3 藍牙BLE初步 2014-07-05 13:49 zhangguangyuan

          怎么一次讀取多個UUID的值呢  回復  更多評論   

          # re: Android4.3 藍牙BLE初步 2014-07-05 13:51 zhangguangyuan

          求指點
          我是先寫01 到下位機
          這是會讀取一個數據包
          緊接著寫02 到下位機,再度去一個數據包

          可是第二個獨步到?  回復  更多評論   

          # re: Android4.3 藍牙BLE初步 2014-08-09 16:50 龍xy

          我能不能接收到藍牙廣播時的數據包,怎么接收。  回復  更多評論   

          # re: Android4.3 藍牙BLE初步[未登錄] 2014-08-12 22:23 yang

          樓主您好,請問有沒有android移動設備作為服務端的程序說明,如果有請多多指教!  回復  更多評論   

          # re: Android4.3 藍牙BLE初步[未登錄] 2014-09-05 00:29 claymore

          你好,樓主,我是一個Android開發新手,我想請教一個問題,就是GATT協議 Android是需要API19的,但是如何去兼容其他低版本的手機呢?  回復  更多評論   

          # re: Android4.3 藍牙BLE初步 2014-09-27 16:10 ming@

          @xchen
          我遇到和你一樣的問題,請問你解決了沒有?苦惱,一直解決不了  回復  更多評論   

          # re: Android4.3 藍牙BLE初步 2014-09-28 16:19 hewuhai

          樓主好:
          想做一個手機更新從機設備數據,手機作為主機連接從機,然后向從機發送400字節的數據,21byte數據包單包發送已經調通,我想采用分包的方式發送這400個字節,但是我不知道怎么確定每一包發送完成且收到正確,對于分包發送400byte的思路不會,請樓主多多指點哈!  回復  更多評論   

          # re: Android4.3 藍牙BLE初步 2014-11-24 10:33 Scienve

          @hewuhai
          可以把在每個數據包的包頭前加上序號,主機收到一個校驗序號是否連續,即可。  回復  更多評論   

          # re: Android4.3 藍牙BLE初步 2014-12-02 17:00 陳導

          請問你如何實現一個client端與兩個設備進行連接的??@Chris
            回復  更多評論   

          # re: Android4.3 藍牙BLE初步[未登錄] 2015-04-27 10:51 channing

          請問 我現在需要將硬件設備的操作數據(比如按上鍵會發送11數據)傳送到app上,如何調用方法呢?我現在已經可以通過app完成對硬件設備基本屬性(比如電量等等)的讀寫。跪求大神指導??!  回復  更多評論   

          # re: Android4.3 藍牙BLE初步[未登錄] 2015-04-27 10:53 channing

          @channing
          簡單來說就是用硬件對app進行操作,如何實現~麻煩你了~  回復  更多評論   

          # re: Android4.3 藍牙BLE初步[未登錄] 2015-06-01 15:42 rock

          @ming@
          請問大神 有方法可以獲得與手機連接的藍牙設備的距離嗎?  回復  更多評論   

          # re: Android4.3 藍牙BLE初步 2015-07-01 16:16 陸小安

          我也試著用你的方法寫,但是依舊只是能搜索出來但是連接不上,而且用官方的demo搜索出來了連接不上 手機用的是三星note4,那個藍牙模塊用ios的可以連上,Android就不行求助  回復  更多評論   

          # re: Android4.3 藍牙BLE初步 2015-07-26 06:56 jjxxjnzy

          @陸小安
          和你碰到了同樣的問題,ios上完全是正常的,但是在android就存在問題,第一次掃描過后,可以正常連接,連接成功以后,給設備發送數據,之后設備斷開,再次開啟搜索,此時設備再也不能被搜索到了,請問你有解決這個問題嗎  回復  更多評論   

          # re: Android4.3 藍牙BLE初步 2015-09-26 17:45 qishuai

          @channing
          @rock
          @jjxxjnzy
          同志們都遇到這樣的問題了,,加個qq一起討論下吧644172593  回復  更多評論   

          # re: Android4.3 藍牙BLE初步 2016-01-12 17:17 crystrl

          您好 我是個新手 剛剛接觸藍牙4.3 我是在做物聯網的項目 現在我的設備用listview把搜索到的藍牙設備裝起來了 現在設置了OnItemClickListener 在這個里面 我要怎么和item的藍牙設備建立連接呢   回復  更多評論   

          公告

          大家好!歡迎光臨我的 Android 技術博客!



          本博客旨在交流與 Android 操作系統相關的各種技術及信息。

          博客內的文章會盡量以開源的形式提供給大家,希望我們能相互交流,共同提高!

          有不足之處,請不吝賜教!

          我的郵箱:zh.weir@gmail.com
          我的新浪微博:@囧虎張建偉

           

          導航

          <2014年2月>
          2627282930311
          2345678
          9101112131415
          16171819202122
          2324252627281
          2345678

          統計

          留言簿(19)

          隨筆分類(24)

          隨筆檔案(18)

          文章檔案(1)

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 大足县| 富源县| 兴和县| 东台市| 新巴尔虎左旗| 大邑县| 积石山| 元谋县| 胶南市| 盱眙县| 南昌县| 岫岩| 宣汉县| 建平县| 焉耆| 宜阳县| 任丘市| 长垣县| 洛扎县| 宜兴市| 沙坪坝区| 缙云县| 延津县| 资源县| 甘肃省| 南投县| 津南区| 长乐市| 广东省| 岳阳市| 洱源县| 株洲市| 琼结县| 江北区| 朝阳区| 南雄市| 文登市| 绥滨县| 如东县| 墨竹工卡县| 伽师县|