To build a better world !

          Android4.3 藍(lán)牙BLE初步


          Android4.3 藍(lán)牙BLE初步

          一、關(guān)鍵概念:

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

          二、角色和職責(zé):

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

          三、權(quán)限及feature:

          和經(jīng)典藍(lán)牙一樣,應(yīng)用使用藍(lán)牙,需要聲明BLUETOOTH權(quán)限,如果需要掃描設(shè)備或者操作藍(lán)牙設(shè)置,則還需要BLUETOOTH_ADMIN權(quán)限:
          <uses-permission android:name="android.permission.BLUETOOTH"/>
          <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
           
          除了藍(lán)牙權(quán)限外,如果需要BLE feature則還需要聲明uses-feature:
          <uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>
           
          按時(shí)required為true時(shí),則應(yīng)用只能在支持BLE的Android設(shè)備上安裝運(yùn)行;required為false時(shí),Android設(shè)備均可正常安裝運(yùn)行,需要在代碼運(yùn)行時(shí)判斷設(shè)備是否支持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();
          }
           
           

          四、啟動(dòng)藍(lán)牙:

          在使用藍(lán)牙BLE之前,需要確認(rèn)Android設(shè)備是否支持BLE feature(required為false時(shí)),另外要需要確認(rèn)藍(lán)牙是否打開。 
          如果發(fā)現(xiàn)不支持BLE,則不能使用BLE相關(guān)的功能。如果支持BLE,但是藍(lán)牙沒打開,則需要打開藍(lán)牙。
           
          打開藍(lán)牙的步驟:
           
          1、獲取BluetoothAdapter
           
          BluetoothAdapter是Android系統(tǒng)中所有藍(lán)牙操作都需要的,它對(duì)應(yīng)本地Android設(shè)備的藍(lán)牙模塊,在整個(gè)系統(tǒng)中BluetoothAdapter是單例的。當(dāng)你獲取到它的示例之后,就能進(jìn)行相關(guān)的藍(lán)牙操作了。
           
          獲取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、判斷是否支持藍(lán)牙,并打開藍(lán)牙
           
          獲取到BluetoothAdapter之后,還需要判斷是否支持藍(lán)牙,以及藍(lán)牙是否打開。
          如果沒打開,需要讓用戶打開藍(lán)牙:
          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設(shè)備:

          通過調(diào)用BluetoothAdapter的startLeScan()搜索BLE設(shè)備。調(diào)用此方法時(shí)需要傳入 BluetoothAdapter.LeScanCallback參數(shù)。
          因此你需要實(shí)現(xiàn) BluetoothAdapter.LeScanCallback接口,BLE設(shè)備的搜索結(jié)果將通過這個(gè)callback返回。
           
          由于搜索需要盡量減少功耗,因此在實(shí)際使用時(shí)需要注意:
           
          1、當(dāng)找到對(duì)應(yīng)的設(shè)備后,立即停止掃描;
          2、不要循環(huán)搜索設(shè)備,為每次搜索設(shè)置適合的時(shí)間限制。避免設(shè)備不在可用范圍的時(shí)候持續(xù)不停掃描,消耗電量。
           
          搜索的示例代碼如下:
          /**
           * 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的外設(shè),你可以調(diào)用 startLeScan(UUID[], BluetoothAdapter.LeScanCallback)方法。
          其中UUID數(shù)組指定你的應(yīng)用程序所支持的GATT Services的UUID。
           
           
          BluetoothAdapter.LeScanCallback的實(shí)現(xiàn)示例如下:
          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();
                     }
                 });
             }
          };
           
          注意:搜索時(shí),你只能搜索傳統(tǒng)藍(lán)牙設(shè)備或者BLE設(shè)備,兩者完全獨(dú)立,不可同時(shí)被搜索。
           
           

          六、連接GATT Server:

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

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

          評(píng)論

          # re: Android4.3 藍(lán)牙BLE初步 2013-12-11 12:56 鵬達(dá)鎖業(yè)

          謝謝博主分享  回復(fù)  更多評(píng)論   

          # re: Android4.3 藍(lán)牙BLE初步 2013-12-23 20:20 yusy

          我現(xiàn)在有個(gè)功能是 手機(jī)APP 向 硬件發(fā)送指令!
          現(xiàn)在我使用上述方法鏈接上了設(shè)備 但是怎么去發(fā)送指令呢?
          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 我要如何獲得,不能隨便找個(gè)UUID我試過了!
          求博主解答,十萬火急,真心感激不盡@鵬達(dá)鎖業(yè)

            回復(fù)  更多評(píng)論   

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

          @yusy

          肯定不能隨便用個(gè)UUID啊。。。

          建議你先看看你的BLE外設(shè)支持的service是什么,如果是用的Bluetooth SIG標(biāo)準(zhǔn)的Profile,你可以在https://developer.bluetooth.org/gatt/profiles/Pages/ProfilesHome.aspx 這個(gè)網(wǎng)站找到對(duì)應(yīng)的service和characteristic的UUID。如果不是標(biāo)準(zhǔn)的,你需要和對(duì)應(yīng)的BLE外設(shè)方案商交流,以獲得相關(guān)資料。  回復(fù)  更多評(píng)論   

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

          您好
          我現(xiàn)在正在嘗試要用Android手機(jī)讀取多個(gè)BLE設(shè)備的值
          看完您的文章後
          我發(fā)覺我原本的做法是Android爲(wèi)Client端去向設(shè)備(Server)要資料
          不過當(dāng)我連線好兩個(gè)設(shè)備時(shí)
          當(dāng)其中一方開始傳送資料時(shí)
          另一方就會(huì)自動(dòng)斷線
          不過單獨(dú)連線一個(gè)設(shè)備取資料都是沒問題的
          想請(qǐng)問是不是Client端沒辦法同時(shí)連線多個(gè)Server?
          感謝!  回復(fù)  更多評(píng)論   

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

          @Chris

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

          # re: Android4.3 藍(lán)牙BLE初步 2014-03-15 12:45 xchen

          android設(shè)備可以作為 Periphreal role么  回復(fù)  更多評(píng)論   

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

          @xchen

          目前還不支持。硬件應(yīng)該是支持的,軟件不支持。  回復(fù)  更多評(píng)論   

          # re: Android4.3 藍(lán)牙BLE初步 2014-03-29 10:37 xchen

          樓主 我用Android 設(shè)備作為中心設(shè)備 ,作為一個(gè)GATT Client端,去連接Ble設(shè)備。第一次是可以成功的,但是藍(lán)牙斷開后再次重連,發(fā)現(xiàn)連不上,從打印的狀態(tài)看是已綁定狀態(tài)。  回復(fù)  更多評(píng)論   

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

          @xchen

          這個(gè)應(yīng)該是你程序邏輯的問題了。應(yīng)該在藍(lán)牙關(guān)閉時(shí)將ble設(shè)備斷開。你可以看看onDisconnect回調(diào)是否有被正常調(diào)起。另外,一些Android手機(jī)在這一塊確實(shí)存在系統(tǒng)穩(wěn)定性的問題。  回復(fù)  更多評(píng)論   

          # re: Android4.3 藍(lán)牙BLE初步 2014-04-15 22:46 xchen

          @zh.weir
          一直沒解決 是協(xié)議層的問題 。謝謝了  回復(fù)  更多評(píng)論   

          # re: Android4.3 藍(lán)牙BLE初步 2014-04-30 16:00 cjolinss

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

          # re: Android4.3 藍(lán)牙BLE初步 2014-07-05 13:49 zhangguangyuan

          怎么一次讀取多個(gè)UUID的值呢  回復(fù)  更多評(píng)論   

          # re: Android4.3 藍(lán)牙BLE初步 2014-07-05 13:51 zhangguangyuan

          求指點(diǎn)
          我是先寫01 到下位機(jī)
          這是會(huì)讀取一個(gè)數(shù)據(jù)包
          緊接著寫02 到下位機(jī),再度去一個(gè)數(shù)據(jù)包

          可是第二個(gè)獨(dú)步到?  回復(fù)  更多評(píng)論   

          # re: Android4.3 藍(lán)牙BLE初步 2014-08-09 16:50 龍xy

          我能不能接收到藍(lán)牙廣播時(shí)的數(shù)據(jù)包,怎么接收。  回復(fù)  更多評(píng)論   

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

          樓主您好,請(qǐng)問有沒有android移動(dòng)設(shè)備作為服務(wù)端的程序說明,如果有請(qǐng)多多指教!  回復(fù)  更多評(píng)論   

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

          你好,樓主,我是一個(gè)Android開發(fā)新手,我想請(qǐng)教一個(gè)問題,就是GATT協(xié)議 Android是需要API19的,但是如何去兼容其他低版本的手機(jī)呢?  回復(fù)  更多評(píng)論   

          # re: Android4.3 藍(lán)牙BLE初步 2014-09-27 16:10 ming@

          @xchen
          我遇到和你一樣的問題,請(qǐng)問你解決了沒有?苦惱,一直解決不了  回復(fù)  更多評(píng)論   

          # re: Android4.3 藍(lán)牙BLE初步 2014-09-28 16:19 hewuhai

          樓主好:
          想做一個(gè)手機(jī)更新從機(jī)設(shè)備數(shù)據(jù),手機(jī)作為主機(jī)連接從機(jī),然后向從機(jī)發(fā)送400字節(jié)的數(shù)據(jù),21byte數(shù)據(jù)包單包發(fā)送已經(jīng)調(diào)通,我想采用分包的方式發(fā)送這400個(gè)字節(jié),但是我不知道怎么確定每一包發(fā)送完成且收到正確,對(duì)于分包發(fā)送400byte的思路不會(huì),請(qǐng)樓主多多指點(diǎn)哈!  回復(fù)  更多評(píng)論   

          # re: Android4.3 藍(lán)牙BLE初步 2014-11-24 10:33 Scienve

          @hewuhai
          可以把在每個(gè)數(shù)據(jù)包的包頭前加上序號(hào),主機(jī)收到一個(gè)校驗(yàn)序號(hào)是否連續(xù),即可。  回復(fù)  更多評(píng)論   

          # re: Android4.3 藍(lán)牙BLE初步 2014-12-02 17:00 陳導(dǎo)

          請(qǐng)問你如何實(shí)現(xiàn)一個(gè)client端與兩個(gè)設(shè)備進(jìn)行連接的??@Chris
            回復(fù)  更多評(píng)論   

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

          請(qǐng)問 我現(xiàn)在需要將硬件設(shè)備的操作數(shù)據(jù)(比如按上鍵會(huì)發(fā)送11數(shù)據(jù))傳送到app上,如何調(diào)用方法呢?我現(xiàn)在已經(jīng)可以通過app完成對(duì)硬件設(shè)備基本屬性(比如電量等等)的讀寫。跪求大神指導(dǎo)!!  回復(fù)  更多評(píng)論   

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

          @channing
          簡(jiǎn)單來說就是用硬件對(duì)app進(jìn)行操作,如何實(shí)現(xiàn)~麻煩你了~  回復(fù)  更多評(píng)論   

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

          @ming@
          請(qǐng)問大神 有方法可以獲得與手機(jī)連接的藍(lán)牙設(shè)備的距離嗎?  回復(fù)  更多評(píng)論   

          # re: Android4.3 藍(lán)牙BLE初步 2015-07-01 16:16 陸小安

          我也試著用你的方法寫,但是依舊只是能搜索出來但是連接不上,而且用官方的demo搜索出來了連接不上 手機(jī)用的是三星note4,那個(gè)藍(lán)牙模塊用ios的可以連上,Android就不行求助  回復(fù)  更多評(píng)論   

          # re: Android4.3 藍(lán)牙BLE初步 2015-07-26 06:56 jjxxjnzy

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

          # re: Android4.3 藍(lán)牙BLE初步 2015-09-26 17:45 qishuai

          @channing
          @rock
          @jjxxjnzy
          同志們都遇到這樣的問題了,,加個(gè)qq一起討論下吧644172593  回復(fù)  更多評(píng)論   

          # re: Android4.3 藍(lán)牙BLE初步 2016-01-12 17:17 crystrl

          您好 我是個(gè)新手 剛剛接觸藍(lán)牙4.3 我是在做物聯(lián)網(wǎng)的項(xiàng)目 現(xiàn)在我的設(shè)備用listview把搜索到的藍(lán)牙設(shè)備裝起來了 現(xiàn)在設(shè)置了OnItemClickListener 在這個(gè)里面 我要怎么和item的藍(lán)牙設(shè)備建立連接呢   回復(fù)  更多評(píng)論   


          只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           

          公告

          大家好!歡迎光臨我的 Android 技術(shù)博客!



          本博客旨在交流與 Android 操作系統(tǒng)相關(guān)的各種技術(shù)及信息。

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

          有不足之處,請(qǐng)不吝賜教!

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

           

          導(dǎo)航

          <2013年12月>
          24252627282930
          1234567
          891011121314
          15161718192021
          22232425262728
          2930311234

          統(tǒng)計(jì)

          留言簿(19)

          隨筆分類(24)

          隨筆檔案(18)

          文章檔案(1)

          搜索

          最新評(píng)論

          閱讀排行榜

          評(píng)論排行榜

          主站蜘蛛池模板: 忻城县| 大田县| 天峻县| 鄂托克前旗| 海宁市| 通渭县| 乐平市| 济宁市| 高唐县| 岳阳市| 上杭县| 兰考县| 乐平市| 缙云县| 宜州市| 仙居县| 襄垣县| 阿勒泰市| 靖远县| 临夏县| 清新县| 灌南县| 泾源县| 上高县| 盈江县| 阳谷县| 紫金县| 健康| 武平县| 安福县| 东兰县| 息烽县| 昌宁县| 长宁县| 台江县| 营山县| 阳春市| 长乐市| 福安市| 岢岚县| 南投市|