Android藍牙總結

因爲之前有做與藍牙有關的項目,所以這裏寫個博客總結一下。
附帶了一個項目以供參考:https://github.com/979451341/BleStudy

一.藍牙操作流程

1.獲取藍牙服務

        mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
        mBluetoothAdapter = mBluetoothManager.getAdapter();
        mBluetoothLeScanner = mBluetoothAdapter.getBluetoothLeScanner();

2.開啓藍牙

mBluetoothAdapter.enable();

3.搜索藍牙設備

    var mScanCallback = object :ScanCallback(){
        override fun onScanResult(callbackType: Int, result: ScanResult?) {
        }
    }
mBluetoothLeScanner.startScan(mScanCallback)

4.連接藍牙設備

//首先獲取設備
        final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
//建立連接獲取BluetoothGatt對象,並設置監聽
        gatts = device.connectGatt(instance, false, mGattCallback);
        

首先說說BluetoothGatt對象,他是藍牙通信的協議,連接藍牙設備,發現服務,向藍牙設備傳數據和接收藍牙設備的數據,都需經過他。
然後我們通過BluetoothGattCallback的,來監聽這些過程。

    private static BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {

        @Override
        public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
            super.onDescriptorWrite(gatt, descriptor, status);
            if (BluetoothGatt.GATT_SUCCESS == status) {
//開啓監聽成功,可以像設備寫入命令了
            } 
        }

        @Override
        public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
            if (newState == BluetoothProfile.STATE_CONNECTED) {
//連接成功
                Log.e(TAG, "設備連接上 開始掃描服務");
                    boolean discoverServices = gatt.discoverServices();
                    if (discoverServices) {
                    } 
            } 
        }

        @Override
        public void onServicesDiscovered(BluetoothGatt gatt, int status) {
            if (status == BluetoothGatt.GATT_SUCCESS) {
            //發現服務
                String address = gatt.getDevice().getAddress();
                //綁定特徵
                bindCharas(address, getSupportedGattServices(address));
            } 
        }

        @Override
        public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
            if (status == BluetoothGatt.GATT_SUCCESS) {
                //characteristic.getValue()爲設備發送的數據,根據數據協議進行解析,對應onCharacteristicRead
            }
        }

        @Override
        public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
            //  characteristic.getValue()爲設備發送的數據,根據數據協議進行解析,對應onCharacteristicChanged
        }

        @Override
        public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
            Log.e(TAG, "發送成功");
        }

        @Override
        public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
            super.onReadRemoteRssi(gatt, rssi, status);
        }
    };

其中綁定特徵需要詳細說說,一個藍牙設備有多個BluetoothGattService服務,一個服務有多個BluetoothGattCharacteristic特徵,一個特徵有多個BluetoothGattDescriptor描述。

其中我們是通過UUID來區別特徵,這個由硬件工程師提供。

我們剛連接藍牙,需要獲取藍牙設備傳過來的數據。首先獲取 read的特徵,然後獲取 通知描述,並給 mBluetoothGatt,使其知道我們需要接受通知

//獲取服務
mBluetoothGatt.getServices()
//獲取read特徵
    private static void bindCharas(String address, List<BluetoothGattService> gattServices) {
        for (BluetoothGattService gattService : gattServices) {
            List<BluetoothGattCharacteristic> gattCharacteristics = gattService.getCharacteristics();
            for (final BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics) {
                String uuid_str = gattCharacteristic.getUuid().toString();
                if (uuid_str.equalsIgnoreCase(Constant.SMART_TAG_READ_UUID)) {
                    BluetoothGattCharacteristic mReadCharacteristic = gattCharacteristic;
                    setCharacteristicNotification(address, mReadCharacteristic, true);
                }
            }
        }
    }

5.手機傳送命令
首先獲取write特徵

        for (BluetoothGattService gattService : mBluetoothGatt.getServices()) {
            uuid = gattService.getUuid().toString();
            List<BluetoothGattCharacteristic> gattCharacteristics = gattService.getCharacteristics();
            // Loops through available Characteristics.
            for (final BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics) {
                uuid = gattCharacteristic.getUuid().toString();
                if (uuid.equalsIgnoreCase(Constant.SMART_TAG_WRITE_UUID)) {
                    return gattCharacteristic;
                }
            }
        }

然後給特徵賦值,給gatt發出命令

            boolean write = characteristic.setValue(cmd);
            mBluetoothGatt.writeCharacteristic(characteristic);

6.斷開藍牙

在我們退出應用時,需斷開連接

gatts.disconnect();
gatts.close();

二.藍牙通信如何寫入項目

1.藍牙通信模塊放哪
我們需要將藍牙通信模塊放在一個生命週期和應用相當的對象裏,比如Application,不過這個類承擔了很多sdk初始化的任務,所以我認爲應該交給Service。

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            startForegroundService(Intent(this, BleService::class.java))
        } else {
            startService(Intent(this, BleService::class.java))
        }

2.數據分發
在Service裏初始化藍牙服務,在BluetoothGattCallback裏監聽藍牙連接的狀況,並通過EventBus發送出去,也可以通過廣播發送出去,我認爲EventBus寫的代碼少一些好用一些。

3.藍牙重連和心跳包
在service的onCeate函數裏,使用Handler或TimerTask完成這個任務

4.使用FastBle框架
https://www.jianshu.com/p/795bb0a08beb

參考文獻
https://juejin.im/post/599b8388f265da249600bbfd

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