Android藍牙開發系列文章-玩轉BLE開發(一)

我們在《Android藍牙開發系列文章-策劃篇》中計劃講解一下藍牙BLE,現在開始第一篇:Android藍牙開發系列文章-玩轉BLE開發(一)。計劃要寫的BLE文章至少分四篇,其他三篇分別講解:BLE Server端編碼(用手機模擬外圍設備),BLE Beacon功能,BLE設備通信(利用自有協議實現Client和Server端通信,在Server端信息改變時,自動上報給Client)。

本文主要內容:編碼實現BLE Client端,實現手機與藍牙體重秤之間的通信

所用的設備華爲榮耀7手機,微信小程序,樂心體重秤

目錄

1.基本概念

2.先來認識一下我們的設備

3、認識BLE Client編碼

3.1 掃描BLE設備

3.2 建立GATT連接

3.3 解析設備支持的characteristic

3.4 讀取characteristic值

3.5 寫characteristic值

3.6 設置indication

4、總結


1.基本概念

在這裏先講解一下BLE(Bluetooth Low Energy)的一些簡單概念。

本文會涉及一個概念叫“GATT連接”,那我們先說一下什麼是GATT,GATT(GenericAttribute Profile)譯爲通用屬性配置文件。GATT連接利用的是在外設(體重秤)與中心設備(手機)之間建議一種聯繫,這種聯繫利用的是雙方之間都能夠識別(或者說提前約定好)的協議。這種協議的基礎就是GATT。

GATT由service、characteristic、descriptor元素組成。service是一個功能單元的集合,這個集合有SIG標準的,也可以自己定義的。一個service可以包含一個或者多個characteristic,每個characteristic包含一個value和一個或者多個descriptor。descriptor是對characteristic的描述,例如是否支持讀取等。

我們說的利用GATT通信就是對characteristic的讀、寫、或者characteristic的值發生改變時的自動上報(方向爲:從藍牙體重秤到手機)。

一個BLE設備往往支持多個service,即多個功能集合。例如,現在智能電視遙控器也許會支持藍牙電量的service、蜂鳴的service以及一些自定義的service。

按照我個人的理解,畫了一個BLE設備的GATT的結構如下,僅供大家參考。

2.先來認識一下我們的設備

俗話說“知彼知己,百戰不殆”,我們在動手碼代碼前,要先來了解一下我們所用的設備,不然代碼寫了一半了,才意識到我們這個功能根本完成不了,那不是呵呵了。

我的測試手機是榮耀7,Android版本爲Android6,因爲BLE是從Android4.3開始支持的,所以我的手機應該可以過關了。

利用微信小程序“BLE藍牙開發助手”可以搜索到家裏的體脂秤,並且可以建立連接。利用該小程序可以看到該款體重秤有4個service,點擊中某個service中的characteristic,可以正常讀取數據,說明手機與體重秤之間建立通信應該沒有問題。

 

下面我們要做的就是實現微信小程序類似的功能,與體重秤建立通信,並獲取數據。

3、認識BLE Client編碼

本文以《Android藍牙開發系列文章-掃不到藍牙設備,你的姿勢對了嗎?》中的代碼爲基礎,進行了添加和修改。

3.1 掃描BLE設備

利用微信小程序,我們可以知道體重秤支持UUID爲“0000FEE7-0000-1000-8000-00805F9B34FB”的service,所以,我在設備過濾條件裏指定了UUID,相關代碼如下:

private void startBleScan2() {
//        mBluetoothLeScanner.startScan(mScanCallback);

        //過濾條件
        List<ScanFilter> bleScanFilters = new ArrayList<>();
//        ScanFilter filter = new ScanFilter.Builder().setDeviceAddress("08:7C:BE:48:65:AD").setServiceUuid(ParcelUuid.fromString("0000fee7-0000-1000-8000-00805f9b34fb")).build();
        ScanFilter filter = new ScanFilter.Builder().setServiceUuid(ParcelUuid.fromString("0000FEE7-0000-1000-8000-00805F9B34FB")).build();
        bleScanFilters.add(filter);
        //掃描設置
        ScanSettings scanSetting = new ScanSettings.Builder().setScanMode(SCAN_MODE_LOW_LATENCY).setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES).setMatchMode(ScanSettings.MATCH_MODE_STICKY).build();
        mBluetoothLeScanner.startScan(bleScanFilters, scanSetting, mScanCallback);
    }

3.2 建立GATT連接

在掃描到目標設備後,我們將BluetoothDevice對象記錄下來。先停掉BLE掃描,然後發起GATT連接。

private  ScanCallback mScanCallback = new ScanCallback() {
    @Override
    public void onScanResult(int callbackType, ScanResult result) {
        super.onScanResult(callbackType, result);
        Log.d(TAG, "onScanResult, result = " + result);
        Message msg = new Message();
        msg.what = MSG_FIND_TARGET;
        msg.obj = result.getDevice();
        mHandler.sendMessage(msg);

    }
};

mHandler = new Handler(){
    @NonNull
    @Override
    public void dispatchMessage(Message msg) {
        Log.d(TAG, "dispatchMessage, msg = " + msg.what);
        switch (msg.what) {
            case MSG_FIND_TARGET:
                mTargetDevice = (BluetoothDevice) msg.obj;
                stopBleScan2();
                mBluetoothGatt = mTargetDevice.connectGatt(getApplicationContext(), false, mBluetoothGattCallback);
                break;
        }
    }
};

GATT連接調用的是BluetoothDevice::connectGatt(Contextcontext,)方法,先說一下參數的含義。

autoConnect表示是否接着發起gatt連接,若值爲false,則表示立即發起連接,若值爲true,則表示爲等到設備變爲available時再發起連接。因爲我們這裏是掃描到設備後發起連接的,所以直接傳入false就OK了。

callback是用於獲取連接狀態改變的回調,該回調是本文的重點,下面詳細講一下。

 

/**
 * Connect to GATT Server hosted by this device. Caller acts as GATT client.
 * The callback is used to deliver results to Caller, such as connection status as well
 * as any further GATT client operations.
 * The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct
 * GATT client operations.
 *
 * @param callback GATT callback handler that will receive asynchronous callbacks.
 * @param autoConnect Whether to directly connect to the remote device (false) or to
 * automatically connect as soon as the remote device becomes available (true).
 * @throws IllegalArgumentException if callback is null
 */
public BluetoothGatt connectGatt(Context context, boolean autoConnect,
        BluetoothGattCallback callback) {
    return (connectGatt(context, autoConnect, callback, TRANSPORT_AUTO));
}

我摘取了部分BluetoothGattCallback中的方法,進行簡單的解釋:

/**
 * This abstract class is used to implement {@link BluetoothGatt} callbacks.
 */
public abstract class BluetoothGattCallback {
    //連接狀態改變的回調,status爲BluetoothGatt#GATT_SUCCESS表示連接成功,
    //newState表示連接狀態改變後的值,可能值爲BluetoothProfile#STATE_DISCONNECTED
    //或者爲BluetoothProfile#STATE_CONNECTED
    public void onConnectionStateChange(BluetoothGatt gatt, int status,
        int newState) {
}
    //調用了BluetoothGatt:: discoverServices()方法的回調
    public void onServicesDiscovered(BluetoothGatt gatt, int status) {
}
//調用了BluetoothGatt::readCharacteristic()方法的回調,在status值爲//BluetoothGatt#GATT_SUCCESS時表示我們想要的值讀取成功了
    public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic,
        int status) {
}
//調用了BluetoothGatt::writeCharacteristic()方法的回調,在status值爲
//BluetoothGatt#GATT_SUCCESS時表示我們對characteristic執行寫操作成功了
    public void onCharacteristicWrite(BluetoothGatt gatt,
        BluetoothGattCharacteristic characteristic, int status) {
}
//在server端的某個characteristic改變時會回調到這裏,當然,前提是設置了//notification
    public void onCharacteristicChanged(BluetoothGatt gatt,
        BluetoothGattCharacteristic characteristic) {
}
//在執行了讀取descriptor的回調,同樣,status值表徵了操作是否成功
    public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor,
        int status) {
}
//在執行了修改descriptor的回調,status值爲BluetoothGatt#GATT_SUCCESS表示修改成了
    public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor,
        int status) {
}
}

3.3 解析設備支持的characteristic

在onConnectionStateChange()回調中,如果status爲BluetoothGatt.GATT_SUCCESS且newState爲BluetoothProfile.STATE_CONNECTED,則可以發起service掃描,即獲取體重秤所支持的service。

如果newState不爲BluetoothProfile.STATE_CONNECTED,則釋放gatt連接資源,並重新發起連接。

@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
    super.onConnectionStateChange(gatt, status, newState);
    Log.d(TAG, "onConnectionStateChange, status = " + status + ", newState = " + newState);
    if (status == BluetoothGatt.GATT_SUCCESS) {
        if (newState == BluetoothProfile.STATE_CONNECTED) {
            mBluetoothGatt.discoverServices();
        } else {
            mBluetoothGatt.close();
            mBluetoothGatt = mTargetDevice.connectGatt(getApplicationContext(), false, mBluetoothGattCallback);
        }
    }
}

在搜索完成體重秤的service後,應用層會收到onServiceDiscovered()回調。我們按照service->characteristic->descriptor層次結構,進行解析。

public void onServicesDiscovered(BluetoothGatt gatt, int status) {
    Log.d(TAG, "onServicesDiscovered, status = " + status);
    List<BluetoothGattService> gattServicesList = mBluetoothGatt.getServices();
    parseService(gattServicesList);

}
private void parseService(List<BluetoothGattService> gattServiceList) {
        Log.d(TAG, "----- start parseServie -----");
        for (int i = 0; i < gattServiceList.size(); i++) {
            BluetoothGattService gattService = (BluetoothGattService)gattServiceList.get(i);
            UUID uuid = gattService.getUuid();
            Log.d(TAG, "parseService, service uuid = " + uuid);

            List<BluetoothGattCharacteristic> gattCharacteristics = gattService.getCharacteristics();
            for (int j = 0; j < gattCharacteristics.size(); j++) {
                BluetoothGattCharacteristic gattCharacteristic = gattCharacteristics.get(j);

                int properties = gattCharacteristic.getProperties();
                int permission = gattCharacteristic.getPermissions();
                Log.d(TAG, "gattCharacteristic, characteristic uuid = " + gattCharacteristic.getUuid() + " properties = " + properties);
                if (0 !=  (properties & BluetoothGattCharacteristic.PROPERTY_READ)) {
                    Log.d(TAG, "gattCharacteristic, characteristic uuid = " + gattCharacteristic.getUuid() + " support read");
                    if (gattCharacteristic.getUuid().toString().equals(LeXinUUID.READ_CHARA)) {
                        Message msg = new Message();
                        msg.what = MSG_READ_CHARA;
                        msg.obj = gattCharacteristic;
                        mHandler.sendMessageDelayed(msg, DELAY_TIMES);
                    }

//                        mBluetoothGatt.readCharacteristic(gattCharacteristic);
                }
                if ((0 !=  (properties & BluetoothGattCharacteristic.PROPERTY_INDICATE))) {
                    Log.d(TAG, "gattCharacteristic, characteristic uuid = " + gattCharacteristic.getUuid() + " support indicate");
                    if (gattCharacteristic.getUuid().toString().equals(LeXinUUID.INDICATE_CHARA)) {
                        Message msg = new Message();
                        msg.what = MSG_INDICATE;
                        msg.obj = gattCharacteristic;
                        mHandler.sendMessageDelayed(msg, 3*DELAY_TIMES);
                    }
                }

                if (0 !=  (properties & BluetoothGattCharacteristic.PROPERTY_NOTIFY)) {
                    Log.d(TAG, "gattCharacteristic, characteristic uuid = " + gattCharacteristic.getUuid() + " support notify");
                }

                if ((0 !=  (properties & BluetoothGattCharacteristic.PROPERTY_WRITE))) {
                    Log.d(TAG, "gattCharacteristic, characteristic uuid = " + gattCharacteristic.getUuid() + " support write");
                    if (gattCharacteristic.getUuid().toString().equals(LeXinUUID.WRITE_CHARA)) {
                        Message msg = new Message();
                        msg.what = MSG_WRITE_CHARA;
                        msg.obj = gattCharacteristic;
                        mHandler.sendMessageDelayed(msg, 2*DELAY_TIMES);
                    }
                }
                List<BluetoothGattDescriptor> gattDescriptors = gattCharacteristic.getDescriptors();
                for (int k = 0; k < gattDescriptors.size(); k++) {
                    BluetoothGattDescriptor gattDescriptor = (BluetoothGattDescriptor)gattDescriptors.get(k);
                    Log.d(TAG, "gattDescriptors, descriptor uuid = " + gattDescriptor.getUuid());
//                        gattDescriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
//                        mBluetoothGatt.writeDescriptor(gattDescriptor);
                }
            }
        }
        Log.d(TAG, "----- parseServie end -----");
    }

在解析的過程中,我們判斷了characteristic的properties是否支持read、write、notify、indicate。解析結果如下:

03-22 21:39:10.794 5392-5429/com.atlas.devicefinder D/MainActivity: ----- start parseServie -----
03-22 21:39:10.794 5392-5429/com.atlas.devicefinder D/MainActivity: parseService, service uuid = 00001800-0000-1000-8000-00805f9b34fb
03-22 21:39:10.794 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 00002a00-0000-1000-8000-00805f9b34fb properties = 10
03-22 21:39:10.794 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 00002a00-0000-1000-8000-00805f9b34fb support read
03-22 21:39:10.794 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 00002a00-0000-1000-8000-00805f9b34fb support write
03-22 21:39:10.794 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 00002a01-0000-1000-8000-00805f9b34fb properties = 2
03-22 21:39:10.794 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 00002a01-0000-1000-8000-00805f9b34fb support read
03-22 21:39:10.794 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 00002a02-0000-1000-8000-00805f9b34fb properties = 10
03-22 21:39:10.794 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 00002a02-0000-1000-8000-00805f9b34fb support read
03-22 21:39:10.794 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 00002a02-0000-1000-8000-00805f9b34fb support write
03-22 21:39:10.794 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 00002a04-0000-1000-8000-00805f9b34fb properties = 2
03-22 21:39:10.794 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 00002a04-0000-1000-8000-00805f9b34fb support read
03-22 21:39:10.794 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 00002a03-0000-1000-8000-00805f9b34fb properties = 14
03-22 21:39:10.794 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 00002a03-0000-1000-8000-00805f9b34fb support read
03-22 21:39:10.794 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 00002a03-0000-1000-8000-00805f9b34fb support write
03-22 21:39:10.794 5392-5429/com.atlas.devicefinder D/MainActivity: parseService, service uuid = 00001801-0000-1000-8000-00805f9b34fb
03-22 21:39:10.794 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 00002a05-0000-1000-8000-00805f9b34fb properties = 34
03-22 21:39:10.795 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 00002a05-0000-1000-8000-00805f9b34fb support read
03-22 21:39:10.795 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 00002a05-0000-1000-8000-00805f9b34fb support indicate
03-22 21:39:10.797 5392-5429/com.atlas.devicefinder D/MainActivity: gattDescriptors, descriptor uuid = 00002902-0000-1000-8000-00805f9b34fb
03-22 21:39:10.797 5392-5429/com.atlas.devicefinder D/MainActivity: parseService, service uuid = 0000fee7-0000-1000-8000-00805f9b34fb
03-22 21:39:10.797 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 0000fec8-0000-1000-8000-00805f9b34fb properties = 32
03-22 21:39:10.797 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 0000fec8-0000-1000-8000-00805f9b34fb support indicate
03-22 21:39:10.799 5392-5429/com.atlas.devicefinder D/MainActivity: gattDescriptors, descriptor uuid = 00002902-0000-1000-8000-00805f9b34fb
03-22 21:39:10.799 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 0000fec9-0000-1000-8000-00805f9b34fb properties = 2
03-22 21:39:10.799 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 0000fec9-0000-1000-8000-00805f9b34fb support read
03-22 21:39:10.799 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 0000fec7-0000-1000-8000-00805f9b34fb properties = 8
03-22 21:39:10.799 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 0000fec7-0000-1000-8000-00805f9b34fb support write
03-22 21:39:10.799 5392-5429/com.atlas.devicefinder D/MainActivity: parseService, service uuid = 0000180a-0000-1000-8000-00805f9b34fb
03-22 21:39:10.799 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 00002a29-0000-1000-8000-00805f9b34fb properties = 2
03-22 21:39:10.799 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 00002a29-0000-1000-8000-00805f9b34fb support read
03-22 21:39:10.799 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 00002a24-0000-1000-8000-00805f9b34fb properties = 2
03-22 21:39:10.799 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 00002a24-0000-1000-8000-00805f9b34fb support read
03-22 21:39:10.799 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 00002a25-0000-1000-8000-00805f9b34fb properties = 2
03-22 21:39:10.799 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 00002a25-0000-1000-8000-00805f9b34fb support read
03-22 21:39:10.799 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 00002a27-0000-1000-8000-00805f9b34fb properties = 2
03-22 21:39:10.799 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 00002a27-0000-1000-8000-00805f9b34fb support read
03-22 21:39:10.799 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 00002a26-0000-1000-8000-00805f9b34fb properties = 2
03-22 21:39:10.799 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 00002a26-0000-1000-8000-00805f9b34fb support read
03-22 21:39:10.799 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 00002a28-0000-1000-8000-00805f9b34fb properties = 2
03-22 21:39:10.799 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 00002a28-0000-1000-8000-00805f9b34fb support read
03-22 21:39:10.799 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 00002a23-0000-1000-8000-00805f9b34fb properties = 2
03-22 21:39:10.799 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 00002a23-0000-1000-8000-00805f9b34fb support read
03-22 21:39:10.799 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 00002a2a-0000-1000-8000-00805f9b34fb properties = 2
03-22 21:39:10.799 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 00002a2a-0000-1000-8000-00805f9b34fb support read
03-22 21:39:10.799 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 00002a50-0000-1000-8000-00805f9b34fb properties = 2
03-22 21:39:10.799 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 00002a50-0000-1000-8000-00805f9b34fb support read
03-22 21:39:10.799 5392-5429/com.atlas.devicefinder D/MainActivity: parseService, service uuid = 0000fee8-0000-1000-8000-00805f9b34fb
03-22 21:39:10.799 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 003784cf-f7e3-55b4-6c4c-9fd140100a16 properties = 16
03-22 21:39:10.800 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 003784cf-f7e3-55b4-6c4c-9fd140100a16 support notify
03-22 21:39:10.801 5392-5429/com.atlas.devicefinder D/MainActivity: gattDescriptors, descriptor uuid = 00002902-0000-1000-8000-00805f9b34fb
03-22 21:39:10.801 5392-5429/com.atlas.devicefinder D/MainActivity: gattDescriptors, descriptor uuid = 00002901-0000-1000-8000-00805f9b34fb
03-22 21:39:10.801 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = 013784cf-f7e3-55b4-6c4c-9fd140100a16 properties = 4
03-22 21:39:10.801 5392-5429/com.atlas.devicefinder D/MainActivity: parseService, service uuid = d618d000-6000-1000-8000-000000000000
03-22 21:39:10.801 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = d618d002-6000-1000-8000-000000000000 properties = 32
03-22 21:39:10.801 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = d618d002-6000-1000-8000-000000000000 support indicate
03-22 21:39:10.803 5392-5429/com.atlas.devicefinder D/MainActivity: gattDescriptors, descriptor uuid = 00002902-0000-1000-8000-00805f9b34fb
03-22 21:39:10.803 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = d618d001-6000-1000-8000-000000000000 properties = 8
03-22 21:39:10.803 5392-5429/com.atlas.devicefinder D/MainActivity: gattCharacteristic, characteristic uuid = d618d001-6000-1000-8000-000000000000 support write
03-22 21:39:10.803 5392-5429/com.atlas.devicefinder D/MainActivity: ----- parseServie end -----

3.4 讀取characteristic值

我們根據上面的解析結果,選取了00002a50-0000-1000-8000-00805f9b34fb來做實驗,在解析到該characteristic時,我們讀取該屬性值,代碼看3.2部分代碼塊。在回調onCharacteristicRead()中添加如下的打印,

public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic,
                                 int status) {
    super.onCharacteristicRead(gatt, characteristic, status);
    Log.d(TAG, "onCharacteristicRead, characteristic = " + characteristic + ", status = " + status + ", value = " + characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT32, 0));
}

實驗結果如下,說明我們收到了相應的回調,因爲我們沒有獲取實際的協議,不知道這個值表示的實際含義。

03-24 21:13:09.645 20927-20938/com.atlas.devicefinder D/MainActivity: onCharacteristicRead, characteristic = android.bluetooth.BluetoothGattCharacteristic@2ac9086, status = 0, value = 1027

3.5 寫characteristic值

我們選取了"0000fec7-0000-1000-8000-00805f9b34fb"characteristic,在解析到該characteristic時,去讀取該屬性值。部分代碼請查看3.2部分的代碼段。
mHandler = new Handler(){
            @NonNull
            @Override
            public void dispatchMessage(Message msg) {
                Log.d(TAG, "dispatchMessage, msg = " + msg.what);
                switch (msg.what) {
                    case MSG_WRITE_CHARA:
                        BluetoothGattCharacteristic gattCharacteristic2 = (BluetoothGattCharacteristic) msg.obj;
                        gattCharacteristic2.setValue("0");
                        mBluetoothGatt.writeCharacteristic(gattCharacteristic2);
                        break;
                }
            }
        };
在回調onCharacteristicWrite()中添加如下的打印,
public void onCharacteristicWrite(BluetoothGatt gatt,
                                  BluetoothGattCharacteristic characteristic, int status) {
    super.onCharacteristicWrite(gatt, characteristic, status);
    Log.d(TAG, "onCharacteristicWrite, characteristic = " + characteristic + ", value = " + characteristic.getStringValue(0) + ", status = " + status);
}
實驗結果如下,說明我們成功修改了該屬性的值。
03-24 21:32:15.318 25167-25167/com.atlas.devicefinder D/MainActivity: dispatchMessage, msg = 2
03-24 21:32:15.385 25167-25366/com.atlas.devicefinder D/MainActivity: onCharacteristicWrite, characteristic = android.bluetooth.BluetoothGattCharacteristic@78102ba, value = 0, status = 0

3.6 設置indication

我們選取了"d618d002-6000-1000-8000-000000000000"characteristic,其持有的descripotor UUID爲"00002902-0000-1000-8000-00805f9b34fb"。

設置方法如下:
mHandler = new Handler(){
            @NonNull
            @Override
            public void dispatchMessage(Message msg) {
                Log.d(TAG, "dispatchMessage, msg = " + msg.what);
                switch (msg.what) {
                    case MSG_INDICATE:
                        BluetoothGattCharacteristic gattCharacteristic3 = (BluetoothGattCharacteristic) msg.obj;
                        boolean ret =mBluetoothGatt.setCharacteristicNotification(gattCharacteristic3, true);
                        BluetoothGattDescriptor descriptor = gattCharacteristic3.getDescriptor(UUID.fromString(LeXinUUID.INDICATE_DES));
                        descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
                        mBluetoothGatt.writeDescriptor(descriptor);
                        break;
                }
            }
        };
在onCharacteristicChanged ()和onDescriptorWrite()中添加如下打印。
public void onCharacteristicChanged(BluetoothGatt gatt,
                                    BluetoothGattCharacteristic characteristic) {
    super.onCharacteristicChanged(gatt, characteristic);
    Log.d(TAG, "onCharacteristicChanged, characteristic = " + characteristic + ", value = " + characteristic.getValue());
}

public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor,
                              int status) {
    super.onDescriptorWrite(gatt, descriptor, status);
    Log.d(TAG, "onDescriptorWrite, descriptor = " + descriptor + ", status = " + status);
}

實際運行結果如下,僅有onDescriptorWrite()的打印,沒有onCharateristicChanged()的打印,可能是因爲我沒有觸發到該屬性值發起改變的緣故(多次嘗試體重測量都沒有回調)。

設置notification的方法跟設置indication類似,只需要對對應的descriptor設置BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE。

綜上,就是BLE Client端編程主要內容。

4、總結

本文重點是開篇的BLE設備的結構,即characteristic是以service爲基礎的,descriptor是以characteristic爲基礎的,我們修改某個characteristic時,先要確定好service是那個。

 

如果想持續關注本博客內容,請掃描關注個人微信公衆號,或者微信搜索:萬物互聯技術。

 

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