Android 藍牙4.0開發

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封裝了對數據全部的處理。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章