1. 程式人生 > >Android4.3 藍芽BLE初步(收藏)

Android4.3 藍芽BLE初步(收藏)

http://www.blogjava.net/zh-weir/archive/2013/12/09/407373.html


Android4.3 藍芽BLE初步

一、關鍵概念:

Generic Attribute Profile (GATT) 通過BLE連線,讀寫屬性類小資料的Profile通用規範。現在所有的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回撥等。