【安卓相關】藍牙開發(fā)、掃描、通知、發(fā)送指令

最近在做藍牙相關的開發(fā),雖然說 FastBleLib 這樣的第三方藍牙連接庫非常方便,但是原生開發(fā)還是有必要了解一下的。

首先說明

1.不需要問硬件工程師UUID
2.不需要寫 UI
3.本案例只有一個類文件
4.沒有寫動態(tài)請求藍牙權限相關的,自己測試過程中,手動開啟所有權限即可。
5.代碼解釋全部寫在注釋,和日志

<uses-permission android:name="android.permission.BLUETOOTH"/>
<!--此權限不開,可能搜不到藍牙設備-->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
public class Main8Activity extends AppCompatActivity {

    //  藍牙適配器對象,用于掃描藍牙設備
    private BluetoothAdapter bluetoothAdapter;

    // GATT 通信,連接藍牙,發(fā)送指令,以及接收藍牙通知 ( 這里所謂的通知,就是藍牙傳過來的數(shù)據(jù) )
    private BluetoothGatt bluetoothGatt;

    //  如果藍牙沒有開啟
    private final static int REQUEST_ENABLE = 100;

    //  掃描到的藍牙設備,因為 Set 不會重復,所以用這個數(shù)據(jù)結構
    private Set<BluetoothDevice> bluetoothDeviceSet;

    //  用戶發(fā)送指令的操作
    private BluetoothGattCharacteristic writeBluetoothGattCharacteristic;

    //  用于開啟通知的操作
    private BluetoothGattCharacteristic notificationBluetoothGattCharacteristic;


    //  服務和特征值
    private UUID write_UUID_service;
    private UUID write_UUID_chara;

    private UUID read_UUID_service;
    private UUID read_UUID_chara;

    private UUID notify_UUID_service;
    private UUID notify_UUID_chara;

    private UUID indicate_UUID_service;
    private UUID indicate_UUID_chara;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main8);


        log("初始化藍牙掃描 的 set 集合");
        bluetoothDeviceSet = new HashSet<>();

        log("開始獲取藍牙適配器");
        bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

        if(bluetoothAdapter != null){

            log("bluetoothAdapter 不為 null 當前設備支持藍牙");

            if(!bluetoothAdapter.isEnabled()){
                log("藍牙未啟動,正在使用 intent 啟用藍牙");
                Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
                startActivityForResult(intent,REQUEST_ENABLE);
            }else{
                log("藍牙已經(jīng)啟動,不需要使用 intent 啟動藍牙");

                bluetoothAdapter.getBluetoothLeScanner().startScan(scanCallback);
                log("開始掃描藍牙設備");
            }

        }else{
            log("bluetoothAdapter 為 null 所以當前設備不支持藍牙");
        }


    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);


        if(requestCode == REQUEST_ENABLE){
            if(resultCode == RESULT_OK){

                log("用戶允許了開啟藍牙的請求");

                log("開始掃描藍牙設備");
                bluetoothAdapter.getBluetoothLeScanner().startScan(scanCallback);

            }else if(resultCode == RESULT_CANCELED){
                log("用戶拒絕了開啟藍牙的請求");
            }
        }


    }




    //  藍牙開始掃描回調(diào)
    private ScanCallback scanCallback = new ScanCallback() {
        @Override
        public void onScanResult(int callbackType, ScanResult result) {
            super.onScanResult(callbackType, result);

            //  bluetoothDevice 為掃描到的藍牙設備
            BluetoothDevice bluetoothDevice = result.getDevice();


            //  添加掃描到的藍牙設備到 set 集合
            boolean addResult = bluetoothDeviceSet.add(bluetoothDevice);


            //  如果 set 集合中未存在該藍牙對象,則返回true
            if(addResult){
                //log("onScanResult() 發(fā)現(xiàn)藍牙設備" + bluetoothDevice.getName() + "," + bluetoothDevice.getAddress());

                //log("目前已經(jīng)發(fā)現(xiàn)" + bluetoothDeviceSet.size() + "個藍牙設備");

                //  如果當前添加的設備 藍牙名稱為 HTC_38908 MAC地址為  88:25:83:F1:04:58,則發(fā)起連接
                //  懶得寫 列表 UI 了,這里先直接指定好自己用來測試藍牙的設備
                if("HTC_38908".equals(bluetoothDevice.getName()) && "88:25:83:F1:04:58".equals(bluetoothDevice.getAddress()) ){

                    log("發(fā)現(xiàn)需要連接的設備");

                    log("因為藍牙掃描比較消耗資源,所以連接前就關閉掃描");

                    //  bluetoothAdapter.stopScan(scanCallback);
                    bluetoothAdapter.cancelDiscovery();

                    log("開始 GATT 通信");
                    bluetoothGatt = bluetoothDevice.connectGatt(Main8Activity.this,true,bluetoothGattCallback);

                }
            }
        }

        @Override
        public void onBatchScanResults(List<ScanResult> results) {
            super.onBatchScanResults(results);
        }

        @Override
        public void onScanFailed(int errorCode) {
            super.onScanFailed(errorCode);
        }
    };


    private BluetoothGattCallback bluetoothGattCallback = new BluetoothGattCallback() {
        @Override
        public void onPhyUpdate(BluetoothGatt gatt, int txPhy, int rxPhy, int status) {
            super.onPhyUpdate(gatt, txPhy, rxPhy, status);
        }

        @Override
        public void onPhyRead(BluetoothGatt gatt, int txPhy, int rxPhy, int status) {
            super.onPhyRead(gatt, txPhy, rxPhy, status);
        }

        @Override
        public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
            super.onConnectionStateChange(gatt, status, newState);


            if(BluetoothGatt.STATE_CONNECTED == newState){      //  藍牙連接狀態(tài)改變 為 -- 已連接

                // 將會回調(diào) 本類中的 onServicesDiscovered() 這個方法
                boolean result = gatt.discoverServices();

                if(result){
                    log("藍牙連接成功");
                }else{
                    log("藍牙連接失敗");
                }

            }else if(BluetoothGatt.STATE_DISCONNECTED == newState){     //  藍牙連接狀態(tài)改變?yōu)?-- 連接斷開

                log("斷開連接");

            }
        }

        @Override
        public void onServicesDiscovered(BluetoothGatt gatt, int status) {
            super.onServicesDiscovered(gatt, status);

            //  這里初始化 各種 服務 和 描述 ,用來發(fā)送藍牙指令的對象,還有接收藍牙數(shù)據(jù)對象
            initServiceAndChara();

        }

        @Override
        public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
            super.onCharacteristicRead(gatt, characteristic, status);

            log("onCharacteristicRead");
        }

        @Override
        public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
            super.onCharacteristicWrite(gatt, characteristic, status);

            log("onCharacteristicWrite");
        }

        @Override
        public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
            super.onCharacteristicChanged(gatt, characteristic);


            //  這里將藍牙傳過來的數(shù)據(jù)轉換為 16 進制格式的字符串,便于閱讀
            byte[] bytes = characteristic.getValue();

            StringBuilder stringBuilder = new StringBuilder();
            for (byte b : bytes) {
                stringBuilder.append(String.format("%02x", b));
            }

            log("藍牙傳回來的內(nèi)容 ( 16進制 ) : " + stringBuilder.toString());
        }

        @Override
        public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
            super.onDescriptorRead(gatt, descriptor, status);

            log("onDescriptorRead");
        }

        @Override
        public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
            super.onDescriptorWrite(gatt, descriptor, status);

            log("onDescriptorWrite");
        }

        @Override
        public void onReliableWriteCompleted(BluetoothGatt gatt, int status) {
            super.onReliableWriteCompleted(gatt, status);

            log("onReliableWriteCompleted");
        }

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

            log("onReadRemoteRssi");
        }

        @Override
        public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {
            super.onMtuChanged(gatt, mtu, status);

            log("onMtuChanged");
        }
    };


    private void initServiceAndChara(){

        List<BluetoothGattService> bluetoothGattServices= bluetoothGatt.getServices();

        for (BluetoothGattService bluetoothGattService:bluetoothGattServices){

            List<BluetoothGattCharacteristic> characteristics=bluetoothGattService.getCharacteristics();

            for (BluetoothGattCharacteristic characteristic:characteristics){


                int charaProp = characteristic.getProperties();


                if ((charaProp & BluetoothGattCharacteristic.PROPERTY_READ) > 0) {
                    read_UUID_chara=characteristic.getUuid();
                    read_UUID_service=bluetoothGattService.getUuid();
                    log("read_chara="+read_UUID_chara+"----read_service="+read_UUID_service);
                }


                if ((charaProp & BluetoothGattCharacteristic.PROPERTY_INDICATE) > 0) {
                    indicate_UUID_chara=characteristic.getUuid();
                    indicate_UUID_service=bluetoothGattService.getUuid();
                    log("indicate_chara="+indicate_UUID_chara+"----indicate_service="+indicate_UUID_service);

                }


                if ((charaProp & BluetoothGattCharacteristic.PROPERTY_WRITE) > 0) {
                    write_UUID_chara=characteristic.getUuid();
                    write_UUID_service=bluetoothGattService.getUuid();
                    log("write_chara="+write_UUID_chara+"----write_service="+write_UUID_service);
                }


                if ((charaProp & BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE) > 0) {
                    write_UUID_chara=characteristic.getUuid();
                    write_UUID_service=bluetoothGattService.getUuid();
                    log("write_chara="+write_UUID_chara+"----write_service="+write_UUID_service);

                    //  寫入服務
                    BluetoothGattService service = bluetoothGatt.getService(write_UUID_service);
                    writeBluetoothGattCharacteristic = service.getCharacteristic(write_UUID_chara);

                    //  發(fā)送指令
                    sendBleData("*".getBytes());

                }


                if ((charaProp & BluetoothGattCharacteristic.PROPERTY_NOTIFY) > 0) {
                    notify_UUID_chara=characteristic.getUuid();
                    notify_UUID_service=bluetoothGattService.getUuid();
                    log("notify_chara="+notify_UUID_chara+"----notify_service="+notify_UUID_service);

                    //  初始化通知服務
                    BluetoothGattService service = bluetoothGatt.getService(notify_UUID_service);
                    notificationBluetoothGattCharacteristic = service.getCharacteristic(notify_UUID_chara);

                    //  開啟通知
                    bluetoothGatt.setCharacteristicNotification(notificationBluetoothGattCharacteristic,true);
                }




            }
        }
    }


    /**
     * 發(fā)送數(shù)據(jù)給藍牙
     * @param data 數(shù)據(jù)byte[]
     * */
    private void sendBleData(byte[] data){
        writeBluetoothGattCharacteristic.setValue(data);
        bluetoothGatt.writeCharacteristic(writeBluetoothGattCharacteristic);
    }


    /**
     * 日志
     * @param log 日志內(nèi)容
     * */
    private void log(String log){
        Log.i("藍牙",log);
    }




}

以上,相信注釋里面已經(jīng)寫的很清楚了。

然后打開日志看就行了

參考

藍牙概覽官方文檔參考
藍牙參考文章

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內(nèi)容