1. 程式人生 > >android ble藍芽開發略解

android ble藍芽開發略解

Android 藍芽4.0開發

1、  許可權和相關屬性

“android:required="true"表示apk只有在具有bluetooth_le屬性的系統裡執行,這個4.3之前android系統沒有

<uses-featureandroid:name="android.hardware.bluetooth_le"android:required="true"/>

<uses-permissionandroid:name="android.permission.BLUETOOTH"/>

<uses-permissionandroid:name="android.permission.BLUETOOTH_ADMIN"/>

2、  程式開媽操作藍芽之前,先判斷ble是否支援

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

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

            finish();

        }

3、  開啟、關閉藍芽

先獲取藍芽的一個代理

final BluetoothManager bluetoothManager =

                (BluetoothManager)getSystemService(Context.BLUETOOTH_SERVICE

);

       mBluetoothAdapter = bluetoothManager.getAdapter();

發intent通知系統開啟藍芽

if(!mBluetoothAdapter.isEnabled()) {

            if (!mBluetoothAdapter.isEnabled()){

                Intent enableBtIntent = newIntent(BluetoothAdapter.ACTION_REQUEST_ENABLE);

               startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);

            }

        }

也可以使用 enable 和disable函式來開啟關閉

4、  搜尋ble裝置

mHandler.postDelayed(newRunnable() {

                @Override

                public void run() {

                    mScanning = false;

                   mBluetoothAdapter.stopLeScan(mLeScanCallback);

                }

            }, SCAN_PERIOD);

            mScanning = true;

           mBluetoothAdapter.startLeScan(mLeScanCallback);

//SCAN_PERIOD是10000,表示每次的搜尋時間為10秒

需要注意的是mLeScanCallback,在4.3之前的api是通過註冊廣播來處理搜尋時發生的一些事件,而支援ble的新的api中,是通過回撥的方式來處理的,mLeScanCallback就是一個介面物件,看一下實現:

privateBluetoothAdapter.LeScanCallback mLeScanCallback =

            newBluetoothAdapter.LeScanCallback() {

        @Override

        public void onLeScan(finalBluetoothDevice device, int rssi, byte[] scanRecord) {

            runOnUiThread(new Runnable() {

                @Override

                public void run() {

                    mLeDeviceListAdapter.addDevice(device);

                   mLeDeviceListAdapter.notifyDataSetChanged();

                }

            });

        }

};

5、  連線

4.3之前的api是通過socket方式在藍芽之間互相通訊,連線的結果是返回一個socket物件

在支援4.0藍芽的新的api中,返回的是BluetoothGatt物件

可以將BluetoothGatt物件看成是遠端裝置的一個代理

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

mGattCallback是一個抽象類物件,之前的廣播形式,在新的api中都改成了回撥

BluetoothGattCallback抽象類,只有9個方法,字面意思就都可以看懂,在處理連線事件上,需要處理方法:

public voidonConnectionStateChange(BluetoothGatt gatt, int status,

                                        intnewState)

條件:if (newState ==BluetoothProfile.STATE_CONNECTED)

else if (newState ==BluetoothProfile.STATE_DISCONNECTED)分別表示已連線和已斷開

6、 通訊

這一點與之前形式上完全不一樣了

BLE分為三部分Service、Characteristic、Descriptor,這三部分都由UUID作為唯一標示符。一個藍芽4.0的終端可以包含多個Service,一個Service可以包含多個Characteristic,一個Characteristic包含一個Value和多個Descriptor,一個Descriptor包含一個Value。

在連線上某個終端後,可以將其每個結點的UUID全部打印出來,但每個結點不是都能讀寫。

一般來說,Characteristic是手機與BLE終端交換資料的關鍵,Characteristic有較多的跟許可權相關的欄位,例如PERMISSION和PROPERTY,而其中最常用的是PROPERTY,本文所用的BLE藍芽模組竟然沒有標準的Characteristic的PERMISSION。Characteristic的PROPERTY可以通過位運算子組合來設定讀寫屬性,例如READ|WRITE、READ|WRITE_NO_RESPONSE|NOTIFY,因此讀取PROPERTY後要分解成所用的組合

我是這麼去和ble終端通訊的:

得到某個service的物件

BluetoothGattService linkLossService =mBluetoothGatt

                                      .getService(UUID.fromString("49535343-fe7d-4ae5-8fa9-9fafd205e455"));

一般說來,ble裝置都帶有幾個標準的服務,其UUID已經定義好了,這些結點裡的值只能讀了,因為我一個一個試過了,終於找到了我的裝置裡可以讀寫的服務,其中49535343-fe7d-4ae5-8fa9-9fafd205e455就是對應這個服務的

獲取此服務結點下的某個Characteristic物件

BluetoothGattCharacteristic alertLevel =linkLossService.getCharacteristic(UUID.fromString("49535343-8841-43f4-a8d4-ecbe34729bb3"));

一般供應商會給出多個Characteristic,你需要找到到底哪個才是讓你去寫的,怎麼找需要看對應的終端的一些開發文件之類的,在這裡我經過測試已經找到我要的了

設定要寫的值

alertLevel.setValue(values_on);

這裡的values_on是一個byte陣列

status = mBluetoothGatt.writeCharacteristic(alertLevel);

status如果為true,表示寫操作已經成功執行,BluetoothGattCallback抽象類的一個方法會被執行,如果剛好你又重寫了這個方法,就可以列印一些訊息了

public void onCharacteristicWrite(BluetoothGatt gatt,

           BluetoothGattCharacteristiccharacteristic, int status)

讀某個Characteristic

public void readCharacteristic(BluetoothGattCharacteristiccharacteristic) {

        if (mBluetoothAdapter == null || mBluetoothGatt == null) {

            Log.w(TAG, "BluetoothAdapter not initialized");

            return;

        }

        mBluetoothGatt.readCharacteristic(characteristic);

}

如果成功,資料會在下面的方法回撥中傳進來

public voidonCharacteristicRead(BluetoothGatt gatt,

                                        BluetoothGattCharacteristic characteristic,

                                         int status)

當終端有資料要傳過來的時候,表面上正常的話,手機這邊下面的方法會被呼叫

public voidonCharacteristicRead(BluetoothGatt gatt,

                                        BluetoothGattCharacteristic characteristic,

                                         intstatus)

這個也是可以控制的,設定descriptor的value不同,可以控制這個重寫的方法是否會被呼叫,沒有測試其他的裝置,感覺這個應該是會對應不同的裝置,具體設定的地方會有不同,在我這邊是這麼操作的:

public void enableNotification(boolean b)

    {

    if(b)

    {

               BluetoothGattService service =mBluetoothGatt

                             .getService(UUID.fromString("49535343-fe7d-4ae5-8fa9-9fafd205e455"));

             BluetoothGattCharacteristicale =service.getCharacteristic(UUID.fromString("49535343-1E4D-4BD9-BA61-23C647249616"));

             booleanset = mBluetoothGatt.setCharacteristicNotification(ale, true);

             Log.d(TAG," setnotification = " + set);

             BluetoothGattDescriptordsc =ale.getDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"));

             byte[]bytes = {0x01,0x00};

        dsc.setValue(bytes);

        boolean success =mBluetoothGatt.writeDescriptor(dsc);

        Log.d(TAG, "writing enabledescriptor:" + success);

    }

    else

    {

               BluetoothGattService service =mBluetoothGatt

                             .getService(UUID.fromString("49535343-fe7d-4ae5-8fa9-9fafd205e455"));

             BluetoothGattCharacteristicale =service.getCharacteristic(UUID.fromString("49535343-1E4D-4BD9-BA61-23C647249616"));

             booleanset = mBluetoothGatt.setCharacteristicNotification(ale, false);

             Log.d(TAG," setnotification = " + set);

             BluetoothGattDescriptordsc =ale.getDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"));

             byte[]bytes = {0x00, 0x00};

        dsc.setValue(bytes);

        boolean success =mBluetoothGatt.writeDescriptor(dsc);

        Log.d(TAG, "writing enabledescriptor:" + success);

    }

    }

7、 總結

網上的一些資料大都以上面的命名來標識自己的文件,有必要解釋一下,應該分開來看這個命題:

android指的安裝的4.3及以上版本的android系統的裝置

4.0藍芽指的藍芽晶片使用4.0協議的裝置

這種開發的一種標準用處是:用4.3以上android版本的手機,與4.0藍芽穿戴式裝置進行通訊

按網上的一種中央與周邊的說法,手機就是中央,4.0藍芽裝置就中周邊

如果要開發4.0藍芽,應該知道4.0藍芽具有高速、低功耗的優點,這些優點對手機的提升不大,但對其他一些終端裝置的提升就比較大。

有意思的是,android對與4.0藍芽通訊的封裝,不需要本身裝置的藍芽晶片是4.0協議的藍芽晶片

於是android 藍芽4.0開發的這麼一個“大環境”下的真實情景就是:一個沒有必要擁有藍芽4.0協議的藍芽晶片的android4.3以上系統的手機,與一些4.0藍芽協議的藍芽晶片裝置終端的故事

以上是一些事實,以下是一些猜想

1、 藍芽4.0與之前版本協議之間可以通訊,說明:4.0藍芽協議並不是修改的無線波的調製與解調,而是修改的資料的組成

2、 對藍芽4.0協議的支援,是由google提出的,而不是各個手機廠商提出的,說明:android系統在軟體上可以一致對待不同的藍芽晶片,不同的藍芽晶片對同一段資料的調製解調結果是一樣的,於是在這段資料通過串列埠傳到手機主控的時候,也是一樣的,在這個環境裡,藍芽晶片只是一個調變解調器,android封裝了對資料全部的處理。