Android 藍牙開發初學

    最近工作中用到了藍牙方面的知識,所以寫此博客記錄一下。

一、藍牙開發需要用到的API都在 android.bluetooth包下   

BluetoothAdapter

表示本地藍牙適配器(藍牙無線裝置)。 BluetoothAdapter 是所有藍牙交互的入口點。 利用它可以發現其他藍牙設備,查詢綁定(配對)設備的列表,使用已知的 MAC 地址實例化 BluetoothDevice,以及創建 BluetoothServerSocket 以偵聽來自其他設備的通信。

BluetoothDevice

表示遠程藍牙設備。利用它可以通過 BluetoothSocket 請求與某個遠程設備建立連接,或查詢有關該設備的信息,例如設備的名稱、地址、類和綁定狀態等。

BluetoothSocket

表示藍牙套接字接口(與 TCP Socket 相似)。這是允許應用通過 InputStream 和 OutputStream 與其他藍牙設備交換數據的連接點。

BluetoothServerSocket

表示用於偵聽傳入請求的開放服務器套接字(類似於 TCP ServerSocket)。 要連接兩臺 Android 設備,其中一臺設備必須使用此類開放一個服務器套接字。 當一臺遠程藍牙設備向此設備發出連接請求時,BluetoothServerSocket 將會在接受連接後返回已連接的 BluetoothSocket

BluetoothClass

描述藍牙設備的一般特徵和功能。 這是一組只讀屬性,用於定義設備的主要和次要設備類及其服務。 不過,它不能可靠地描述設備支持的所有藍牙配置文件和服務,而是適合作爲設備類型提示。

BluetoothProfile

表示藍牙配置文件的接口。 藍牙配置文件是適用於設備間藍牙通信的無線接口規範。

BluetoothHeadset

提供藍牙耳機支持,以便與手機配合使用。

BluetoothA2dp

定義高質量音頻如何通過藍牙連接和流式傳輸,從一臺設備傳輸到另一臺設備。“A2DP”代表高級音頻分發配置文件。

BluetoothHealth

表示用於控制藍牙服務的健康設備配置文件代理。

BluetoothHealthCallback

用於實現 BluetoothHealth 回調的抽象類。您必須擴展此類並實現回調方法,以接收關於應用註冊狀態和藍牙通道狀態變化的更新內容。

BluetoothHealthAppConfiguration

表示第三方藍牙健康應用註冊的應用配置,以便與遠程藍牙健康設備通信。

BluetoothProfile.ServiceListener

在 BluetoothProfile IPC 客戶端連接到服務(即,運行特定配置文件的內部服務)或斷開服務連接時向其發送通知的接口

官方文檔地址:https://developer.android.com/guide/topics/connectivity/bluetooth,有興趣可以去看看,上面說的很詳細。

二 、要用到的權限

6.0以下

<!-- 使用藍牙的權限 -->

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

<!-- 掃描藍牙設備或者操作藍牙設置 -->

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

6.0以上

<!-- 使用藍牙的權限 -->

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

<!-- 掃描藍牙設備或者操作藍牙設置 -->

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

<!--模糊定位權限,僅作用於6.0+-->

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

<!--精準定位權限,僅作用於6.0+-->

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

三、開發工作

1. 流程:動態權限檢查---->獲取藍牙適配器---->啓用藍牙---->查找設備---->配對與連接

流程大概就是這樣,權限檢查就不說了,應該都會,不會可以自己找找相關博客看下。

2. 首先打開藍牙,打開藍牙大概有兩種方式

  • 2.1 提示用戶跳轉到設置界面打開
if (!mBluetoothAdapter.isEnabled()) {
    Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
    startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
  • 2.2  不提示靜默打開
if (mBluetoothAdapter.isEnabled ()){
            mBluetoothAdapter.enable ();    
   }
  • 2.3 查詢已配對的藍牙
Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
// If there are paired devices
if (pairedDevices.size() > 0) {
    // Loop through paired devices
    for (BluetoothDevice device : pairedDevices) {
        // Add the name and address to an array adapter to show in a ListView
        mArrayAdapter.add(device.getName() + "\n" + device.getAddress());
    }
}
  • 2.4 掃描設備
/**
     * 開始藍牙掃描
     *
     * @return
     */
    public boolean startScan() {
        if (!isBlueEnable()) {
            Log.e(TAG, "Bluetooth not enable!");
            return false;
        }
        //當前是否在掃描,如果是就取消當前的掃描,重新掃描
        if (mBluetoothAdapter.isDiscovering()) {
            mBluetoothAdapter.cancelDiscovery();
        }
        //此方法是個異步操作,一般搜索12秒
        return mBluetoothAdapter.startDiscovery();
    }

註冊廣播,通過廣播接收藍牙信息,我這裏是有一個回調接口

 /**
     * 註冊廣播
     */
    public void registerReceiver() {
        IntentFilter filter1=new IntentFilter (android.bluetooth.BluetoothAdapter.ACTION_DISCOVERY_STARTED);
        IntentFilter filter2=new IntentFilter (android.bluetooth.BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
        IntentFilter filter3=new IntentFilter (BluetoothDevice.ACTION_FOUND);
        registerReceiver (scanBlueReceiver, filter1);
        registerReceiver (scanBlueReceiver, filter2);
        registerReceiver (scanBlueReceiver, filter3);
    }
public class ScanBlueReceiver extends BroadcastReceiver {
    private static final String TAG = ScanBlueReceiver.class.getName();
    private ScanBlueCallBack callBack;

    public ScanBlueReceiver(ScanBlueCallBack callBack) {
        this.callBack = callBack;
    }

    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        Log.d(TAG, "action:" + action);
        BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
        switch (action) {
            case BluetoothAdapter.ACTION_DISCOVERY_STARTED:
                Log.d(TAG, "開始掃描...");
                callBack.onScanStarted();
                break;
            case BluetoothAdapter.ACTION_DISCOVERY_FINISHED:
                Log.d(TAG, "結束掃描...");
                callBack.onScanFinished();
                break;
            case BluetoothDevice.ACTION_FOUND:
                Log.d(TAG, "發現設備...");
                callBack.onScanning(device);
                break;
        }
    }
}

2.5 藍牙配對

首先需要用到 ClsUtils 類,這個網上都有,我就不貼出來了,感謝大神們的奉獻。

藍牙配對需要和目標設備建立連接,這裏需要用到上文說的BluetoothSocket

/**
 * 藍牙連接線程
 */
public class ConnectBlueTask extends AsyncTask<BluetoothDevice, Integer, BluetoothSocket> {

    private static final String TAG = ConnectBlueTask.class.getName();
    private BluetoothDevice bluetoothDevice;
    private ConnectBlueCallBack callBack;

    public ConnectBlueTask(ConnectBlueCallBack callBack){
        this.callBack = callBack;
    }
    UUID SERIAL_UUID = UUID.fromString("00001101-0000-1000-8000-00805f9b34fb");
    @Override
    protected BluetoothSocket doInBackground(BluetoothDevice... bluetoothDevices) {
        bluetoothDevice = bluetoothDevices[0];
        Log.e (TAG, "doInBackground: "+bluetoothDevice.getAddress ());
        BluetoothSocket socket = null;
        try{
            Log.d(TAG,"開始連接socket,uuid:" );
            socket = bluetoothDevice.createRfcommSocketToServiceRecord(SERIAL_UUID);
            if (socket != null && !socket.isConnected()){
                socket.connect();
            }
        }catch (IOException e){
            Log.e(TAG,"socket連接失敗");
            try {
                socket =(BluetoothSocket) bluetoothDevice.getClass().getMethod("createRfcommSocket", new Class[] {int.class}).invoke(bluetoothDevice,1);
                socket.connect();
               // socket.close();
            } catch (IOException e1) {
                e1.printStackTrace();
            } catch (IllegalAccessException e1) {
                e1.printStackTrace ();
            } catch (InvocationTargetException e1) {
                e1.printStackTrace ();
            } catch (NoSuchMethodException e1) {
                e1.printStackTrace ();
            }
        }
        return socket;
    }
    @Override
    protected void onPreExecute() {
        Log.d(TAG,"開始連接");
        if (callBack != null) callBack.onStartConnect();
    }

    @Override
    protected void onPostExecute(BluetoothSocket bluetoothSocket) {
        if (bluetoothSocket != null && bluetoothSocket.isConnected()){
            Log.d(TAG,"連接成功");
            if (callBack != null) callBack.onConnectSuccess(bluetoothDevice, bluetoothSocket);
        }else {
            Log.d(TAG,"連接失敗");
            if (callBack != null) callBack.onConnectFail(bluetoothDevice, "連接失敗");
        }
    }
}

同樣需要註冊相應廣播,用來獲取配對狀態

public void pinRegisterReceiver() {
        IntentFilter filter4=new IntentFilter (BluetoothDevice.ACTION_PAIRING_REQUEST);
        IntentFilter filter5=new IntentFilter (BluetoothDevice.ACTION_BOND_STATE_CHANGED);
        registerReceiver (pinBlueReceiver, filter4);
        registerReceiver (pinBlueReceiver, filter5);
    }
 private String pin="0000";  // 此處爲你要連接的藍牙設備的初始密鑰,一般爲1234或0000
    private static final String TAG=PinBlueReceiver.class.getName ();
    private PinBlueCallBack callBack;

    public PinBlueReceiver(PinBlueCallBack callBack) {
        this.callBack=callBack;
    }

    @Override
    public void onReceive(Context context, Intent intent) {
        String action=intent.getAction ();
        Log.d (TAG, "action:" + action);
        BluetoothDevice device=intent.getParcelableExtra (BluetoothDevice.EXTRA_DEVICE);

        if (BluetoothDevice.ACTION_PAIRING_REQUEST.equals (action)) {
            try {
                callBack.onBondRequest ();
                // 開始配對
                boolean ret=ClsUtils.setPin (device.getClass (), device, pin);
                abortBroadcast ();// 將廣播終止,否則會出現一個一閃而過的配對框。
                //Method removeBondMethod = device.getClass().getDeclaredMethod("setPin", new Class[]{byte[].class});
                //Boolean returnValue = (Boolean) removeBondMethod.invoke(device, new Object[]{pin.getBytes()});
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace ();
            }
        } else if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals (action)) {
            switch (device.getBondState ()) {
                case BluetoothDevice.BOND_NONE:
                    Log.d (TAG, "取消配對");
                    callBack.onBondFail (device);
                    break;
                case BluetoothDevice.BOND_BONDING:
                    Log.d (TAG, "配對中");
                    callBack.onBonding (device);
                    break;
                case BluetoothDevice.BOND_BONDED:
                    Log.d (TAG, "配對成功");
                    callBack.onBondSuccess (device);
                    break;
            }
        }
    }

大概就是這樣。。

參考:https://blog.csdn.net/zqf_888/article/details/81060606 這篇文章寫得很好,建議觀看。

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