Android 藍(lán)牙4.0入門開發(fā)

本文針對一對一的藍(lán)牙進(jìn)行通訊,適合沒有開發(fā)過藍(lán)牙的同學(xué)來看,也適合大部分物聯(lián)網(wǎng)簡單開發(fā),沒有深入藍(lán)牙的開發(fā)。對于沒有開發(fā)過藍(lán)牙的來說,我先說下邏輯。比如先拿自己手機(jī)的藍(lán)牙來說,打開藍(lán)牙,列出列表,包含已經(jīng)配對過的和可用設(shè)備, 點(diǎn)擊其中一個(gè)進(jìn)行配對,配對完成就可以進(jìn)行文件傳輸?shù)韧ㄐ殴δ芰?。所以對于藍(lán)牙開發(fā),大致以下步驟

1.打開藍(lán)牙

2.藍(lán)牙掃描,列出可用設(shè)備

3.關(guān)閉藍(lán)牙掃描(不關(guān)閉會(huì)一直掃描)

4.找到目標(biāo)藍(lán)牙設(shè)備進(jìn)行連接

5.連接成功,進(jìn)行通信

6.關(guān)閉藍(lán)牙釋放資源

接下來我們要根據(jù)上面6個(gè)步驟進(jìn)行API的說明,在說明前,我先說明一下

(1)Service藍(lán)牙功能集合,每一個(gè)Service都有一個(gè)UUID,

(2)Characteristic 在service中也有好多個(gè)Characteristic 獨(dú)立數(shù)據(jù)項(xiàng),其中也有獨(dú)立UUID

上面的兩個(gè)uuid需要從硬件工程師中獲取,這樣你才能匹配到你要的。

(3)BluetoothAdapter 藍(lán)牙的打開關(guān)閉等基本操作

(4)BluetoothDevice 藍(lán)牙設(shè)備,掃描到的

(5)BluetoothGatt 藍(lán)牙連接重連斷開連接等操作的類

(6)BluetoothGattCharacteristic 數(shù)據(jù)通信操作類,讀寫等操作

1.打開藍(lán)牙

需要權(quán)限

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

BluetoothAdapter 這個(gè)類就是藍(lán)牙的基本操作,比如打開關(guān)閉等

初始化藍(lán)牙,得到BluetoothAdapter

private void initBlueTooth() {
    BluetoothManager manager = (BluetoothManager) getSystemService(BLUETOOTH_SERVICE);
    if (manager != null) {
        bluetoothAdapter = manager.getAdapter();
        if (bluetoothAdapter != null) {
            //藍(lán)牙沒有打開
            if (!bluetoothAdapter.isEnabled()) {
                openBle();
            } else {
                Toast.makeText(MainActivity.this, "藍(lán)牙已打開", Toast.LENGTH_SHORT).show();
                scanLeDevice(true);
            }
        } else {
            openBle();
        }
    }
}

打開藍(lán)牙

   private void openBle() {
   //以下兩種方式 第二種方式在onActivityResult處理回調(diào)
//        boolean enable = bluetoothAdapter.enable();//打開藍(lán)牙'直接打開,用戶不知權(quán),用于定制系統(tǒng)'
//        Toast.makeText(MainActivity.this, "正在打開藍(lán)牙", Toast.LENGTH_SHORT).show();
//        if (enable) {
//            Log.e("open",enable+"");
//            new Handler().postDelayed(new Runnable() {
//                @Override
//                public void run() {
//                    scanLeDevice(true);
//                }
//            },2000);
//
//        }
?
        //提示用戶正在打開藍(lán)牙
        Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
        startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
?
?
    }

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (resultCode == RESULT_OK && requestCode == REQUEST_ENABLE_BT) {
        scanLeDevice(true);
    }
}

2.3.打開或者停止掃描,放在同一個(gè)方法中

/**
 * 打開或者停止掃描
 *
 * @param enable
 */
private void scanLeDevice(final boolean enable) {
?
    if (enable) {
        mScanning = true;
        // 定義一個(gè)回調(diào)接口供掃描結(jié)束處理
        bluetoothAdapter.startLeScan(mLeScanCallback);
        // 預(yù)先定義停止藍(lán)牙掃描的時(shí)間(因?yàn)樗{(lán)牙掃描需要消耗較多的電量)
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                mScanning = false;
                bluetoothAdapter.stopLeScan(mLeScanCallback);
            }
        }, SCAN_PERIOD);
?
    } else {
        mScanning = false;
        bluetoothAdapter.stopLeScan(mLeScanCallback);
    }
}

掃描回調(diào),回調(diào)之后得到 BluetoothDevice 的集合,可以放到列表中去

/**
 * 掃描回調(diào)
 */
private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() {
    @Override
    public void onLeScan(BluetoothDevice bluetoothDevice, int i, byte[] bytes) {
        if (bluetoothDevice.getName() != null) {
            if (!bluetoothDeviceArrayList.contains(bluetoothDevice)) {//去下重
                bluetoothDeviceArrayList.add(bluetoothDevice);
            }
            Log.e(TAG, "scan--" + bluetoothDevice.getName());
        }
    }
};

4.5.進(jìn)行藍(lán)牙連接

/**
 * 連接藍(lán)牙 參數(shù)為目標(biāo)設(shè)備
/
public void connectBle(BluetoothDevice bluetoothDevice) {
    mBluetoothDevice = bluetoothDevice;
    if (bluetoothDevice != null) {
        //第二個(gè)參數(shù) 是否重連
        mBluetoothGatt = bluetoothDevice.connectGatt(MainActivity.this, false, bluetoothGattCallback);
    }
?
}

連接回調(diào)

  /**
     * 藍(lán)牙連接成功回調(diào)
     */
?
    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);
        }
?
        //不要執(zhí)行耗時(shí)操作
        @Override
        public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
            super.onConnectionStateChange(gatt, status, newState);
            if (newState == BluetoothProfile.STATE_CONNECTED) {//連接成功
                Log.e(TAG, "onConnectionStateChange 藍(lán)牙連接");
                //這里要執(zhí)行以下方法,會(huì)在onServicesDiscovered這個(gè)方法中回調(diào),如果在                        //onServicesDiscovered方法中回調(diào)成功,設(shè)備才真正連接起來,正常通信
                gatt.discoverServices();
            } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
                Log.e(TAG, "onConnectionStateChange 藍(lán)牙斷連");
                if (mBluetoothDevice != null) {
                    //關(guān)閉當(dāng)前新的連接
                    gatt.close();
                    characteristic = null;
                 
                }
?
            }
?
        }
?
        @Override
        public void onServicesDiscovered(BluetoothGatt gatt, int status) {
            super.onServicesDiscovered(gatt, status);
            //回調(diào)之后,設(shè)備之間才真正通信連接起來
            if (status == BluetoothGatt.GATT_SUCCESS) {
                Log.e(TAG, "onServicesDiscovered 藍(lán)牙連接正常");
                BluetoothGattService service = gatt.getService(UUID.fromString(BleConstantValue.serverUuid));//uuid從硬件工程師獲取
                characteristic = service.getCharacteristic(UUID.fromString(BleConstantValue.charaUuid));
                gatt.readCharacteristic(characteristic);//執(zhí)行之后,會(huì)執(zhí)行下面的                onCharacteristicRead的回調(diào)方法
                //設(shè)置通知,一般設(shè)備給手機(jī)發(fā)送數(shù)據(jù),需要以下監(jiān)聽
                setCharacteristicNotification(characteristic, true);
                //耗時(shí)操作,如果有ui操作,需要用到handler
                adapterFreshHandler.sendEmptyMessage(0);
            } else {
                Log.e(TAG, "onServicesDiscovered 藍(lán)牙連接失敗");
            }
?
        }
?
        //這個(gè)方法一般用不到
        @Override
        public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
            super.onCharacteristicRead(gatt, characteristic, status);
            Log.e(TAG, "callback characteristic read status " + status
                    + " in thread " + Thread.currentThread());
            if (status == BluetoothGatt.GATT_SUCCESS) {
                Log.e(TAG, "read value: " + characteristic.getValue());
            }
?
?
        }
?
        //這個(gè)方法是寫入數(shù)據(jù)時(shí)的回調(diào),可以和你寫入的數(shù)據(jù)做對比
        @Override
        public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
            super.onCharacteristicWrite(gatt, characteristic, status);
            Log.e(TAG, "write value: " + FormatUtil.bytesToHexString(characteristic.getValue()));
        }
?
        //設(shè)備發(fā)出通知時(shí)會(huì)調(diào)用到該接口,藍(lán)牙設(shè)備給手機(jī)發(fā)送數(shù)據(jù),在這個(gè)方法接收
        @Override
        public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
            super.onCharacteristicChanged(gatt, characteristic);
            Log.e(TAG, "接收:" + FormatUtil.bytesToHexString(characteristic.getValue()));//byte[]轉(zhuǎn)為16進(jìn)制字符串
            bleWriteReceiveCallback();
        }
    };
?
/**
* 設(shè)置通知
/
public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic, boolean enabled) {
        if (bluetoothAdapter == null || mBluetoothGatt == null) {
            return;
        }
        mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
    }

參考寫入指令

/**
 * 寫入命令
 */
private void write(byte[] cmd) {
    if (characteristic != null) {
        // 發(fā)出數(shù)據(jù)
        characteristic.setValue(cmd);
        if (mBluetoothGatt.writeCharacteristic(characteristic)) {
            Log.e(TAG, "寫入成功");
        } else {
            Log.e(TAG, "寫入失敗");
        }
    } else {
        Toast.makeText(MainActivity.this, "藍(lán)牙未連接", Toast.LENGTH_SHORT).show();
    }
}

6.斷開連接 釋放資源

/**
 * 斷開藍(lán)牙設(shè)備
 */
public void bleDisConnectDevice(BluetoothDevice device) {
    if (mBluetoothGatt != null) {
        mBluetoothGatt.disconnect();
    }
}
?
 /**
     * 釋放資源 
     */
?
    private void releaseResource() {
        Log.e(TAG, "斷開藍(lán)牙連接,釋放資源");
        if (mBluetoothGatt != null) {
            mBluetoothGatt.disconnect();
            mBluetoothGatt.close();
        }
    }

最后別忘了藍(lán)牙廣播:

 /**
     * 注冊藍(lán)牙監(jiān)聽廣播
     */
    private void registerBleListenerReceiver() {
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
        intentFilter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);
        intentFilter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
        registerReceiver(bleListenerReceiver, intentFilter);
    }
 /**
     * 藍(lán)牙監(jiān)聽廣播接受者
     */
    private BroadcastReceiver bleListenerReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
        //連接的設(shè)備信息
        BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
        Log.e(TAG, "藍(lán)牙廣播" + action);

        if (mBluetoothDevice != null && mBluetoothDevice.equals(device)) {
            Log.e(TAG, "收到廣播-->是當(dāng)前連接的藍(lán)牙設(shè)備");

            if (BluetoothDevice.ACTION_ACL_CONNECTED.equals(action)) {
                Log.e(TAG,"廣播 藍(lán)牙已經(jīng)連接");

            } else if (BluetoothDevice.ACTION_ACL_DISCONNECTED.equals(action)) {
                Log.e(TAG,"廣播 藍(lán)牙斷開連接");
            }
        } else {
            Log.e(TAG, "收到廣播-->不是當(dāng)前連接的藍(lán)牙設(shè)備");
        }

        if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) {
            int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
            switch (state) {
                case BluetoothAdapter.STATE_OFF:
                    Log.e(TAG, "STATE_OFF 藍(lán)牙關(guān)閉");
                    adapter.clear();
                    releaseResource();
                    break;
                case BluetoothAdapter.STATE_TURNING_OFF:
                    Log.e(TAG, "STATE_TURNING_OFF 藍(lán)牙正在關(guān)閉");
                    //停止藍(lán)牙掃描
                    scanLeDevice(false);
                    break;
                case BluetoothAdapter.STATE_ON:
                    Log.d(TAG, "STATE_ON 藍(lán)牙開啟");
                    //掃描藍(lán)牙設(shè)備
                    scanLeDevice(true);
                    break;
                case BluetoothAdapter.STATE_TURNING_ON:
                    Log.e(TAG, "STATE_TURNING_ON 藍(lán)牙正在開啟");
                    break;
            }
        }
        }
    };

所有完成,基本的藍(lán)牙操作及通信功能,通信協(xié)議需要和藍(lán)牙硬件廠商工程師獲取。本文適合藍(lán)牙入門開發(fā),如有錯(cuò)誤請指正 https://github.com/Leaderpaking/ble

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

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