1. 程式人生 > >Android手機藍芽總結之傳統藍芽

Android手機藍芽總結之傳統藍芽

出處:Android手機藍芽總結之傳統藍芽

 

最近,公司有一個專案時關於手機藍芽和硬體藍芽相互通訊的需求。基於之前很久沒有學習硬體的知識,這次記錄下來,以備下次需要時使用。

首先,需要搞清楚一些基本的概要,藍芽3.0以前的是傳統藍芽,4.0以後的是低功耗藍芽,Android藍芽在不同手機系統版本也有不同的藍芽,當然也有不一樣的呼叫方法。android4.3(API18)版本以下的對應的是傳統藍芽,在掃描的時候等待時間會比較長。android4.3以上的是低功耗藍芽,但是android4.3版本到5.0版本的呼叫方法和android5.0以上的呼叫方法是不一樣的。android用傳統的藍芽連線方式是無法和低功耗藍芽模組建立通訊通道的,因為通訊的協議是不一樣的。低功耗藍芽是用GATT這種屬性傳輸協議,而傳統藍芽則是通過Socket的方式進行資料的傳輸。

android藍芽許可權在6.0以上增加了一個模糊定位的許可權,不開啟部分手機無法進行掃描藍芽發出的廣播。

藍芽許可權:

為了能夠在你開發的應用裝置中使用藍芽功能,必須宣告藍芽的許可權"BLUETOOTH"。在進行藍芽的通訊,例如請求連線,接受連線以及交換資料中,需要用到該許可權。

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

如果你的應用程式需要例項化藍芽裝置的搜尋或者對藍芽的設定進行操作,那麼必須宣告BLUETOOTH_ADMIN許可權。大多數應用需要該許可權對本地的藍芽裝置進行搜尋。該許可權的其他能力並不應當被使用,除非你的應用是一個電源管理的應用,需要對藍芽的設定進行修改

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

android 6.0版本之後增加模糊定位授權,如果不增加這個許可權部分6.0以上的手機無法掃描出藍芽。

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

開啟關閉藍芽:

在使用藍芽通訊之前,需要先開啟,使用BluetoothAdapter來進行完成

BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if(mBluetoothAdapter ==null) {// Device does not support Bluetooth}

如果BluetoothAdapter為null值,則表示此手機不支援藍芽功能。

if(!mBluetoothAdapter.isEnabled()){ 
   Intent enableBtIntent =newIntent(BluetoothAdapter.ACTION_REQUEST_ENABLE); 
   startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}

REQUEST_ENABLE_BT大於0的自己定義的int變數。isEnable()判斷藍芽是否可用。推薦使用這種方式進行開啟藍芽。

還有另一種方式開啟,但是在部分手機不會彈出藍芽的授許可權頁。

mBluetoothAdapter.enable()也能直接開啟藍芽。

搜尋裝置:

首先找到手機找出已匹配的藍芽裝置:

// 將已配對的裝置新增到列表中
Set pairedDevices = mBluetoothAdapter.getBondedDevices();
if (pairedDevices.size() > 0) {
    for (BluetoothDevice device : pairedDevices) {
        mDevicesArray.add(device.getName() + "\n" + device.getAddress());
        deviceList.add(device);
    }
}

註冊廣播接收器並開啟掃描:

IntentFilter filter = new IntentFilter();
 //註冊裝置被發現時的廣播
filter.addAction(BluetoothDevice.ACTION_FOUND);
 //註冊一個搜尋結束時的廣播  
filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
registerReceiver(mReceiver, filter);

廣播接收器:

public class BluetoothReceiver extends BroadcastReceiver {
    public final String TAG = getClass().getName();
    private BluetoothInterface bluetoothInterface;
    private List<BluetoothDevice> beans = null;

    public BluetoothReceiver(BluetoothInterface bluetoothInterface) {
        this.bluetoothInterface = bluetoothInterface;
        beans = new ArrayList<>();
    }

    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        //發現藍芽廣播
        if (action.equals(BluetoothDevice.ACTION_FOUND)) {
            BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
            beans.add(device);
            //顯示已配對裝置
            if (device.getBondState() == BluetoothDevice.BOND_BONDED) {
                Log.e(TAG, "\n" + device.getName() + "==>" + device.getAddress() + "\n");
            } else if (device.getBondState() != BluetoothDevice.BOND_BONDED) {
                Log.e(TAG, "\n" + device.getName() + "==>" + device.getAddress() + "\n");
            }
        //搜尋完成回撥
        } else if (action.equals(BluetoothAdapter.ACTION_DISCOVERY_FINISHED)) {
            bluetoothInterface.discoveryCompleted(beans);
        }
    }
}

只要搜尋沒有完成,會一直接收外部藍芽裝置傳送的廣播。如果找到了對應的藍芽裝置,可以取消搜尋。

mBluetoothAdapter.cancelDiscovery();

匹配和連線藍芽

匹配藍芽

//MY_UUID是藍芽串列埠服務對應的應用UUID,網上有說不能寫在UI執行緒,但我寫在UI執行緒也沒問題
BluetoothSocket socket =device.createRfcommSocketToServiceRecord(MY_UUID);

連線藍芽

public class ConnectedThread extends Thread {
    private final BluetoothSocket mSocket;
    private final InputStream mInStream;
    private final OutputStream mOutStream;
    private Handler mHandler;
    public final static int MESSAGE_READ = 1;
    public final static int MESSAGE_EXCEPTIONS = 2;
    public final static int MESSAGE_SUCCESS = 3;

    public ConnectedThread(BluetoothSocket socket, Handler handler) {
        mSocket = socket;
        mHandler = handler;
        InputStream temIn = null;
        OutputStream temOut = null;
        try {
            temIn = socket.getInputStream();
            temOut = socket.getOutputStream();
        } catch (IOException e) {

        }
        mInStream = temIn;
        mOutStream = temOut;
    }

    @Override
    public void run() {
        try {
            mSocket.connect();
            mHandler.sendEmptyMessage(MESSAGE_SUCCESS);
        } catch (IOException e) {
            e.printStackTrace();
            mHandler.sendEmptyMessage(MESSAGE_EXCEPTIONS);
            try {
                mSocket.close();
            } catch (IOException e1) {
                e1.printStackTrace();
            }
        }
        int bytes;
        //對輸入流保持監聽直至一個異常發生
        while (true) {
            byte[] buffer = new byte[20];
            try {
                bytes = mInStream.read(buffer);
                mHandler.obtainMessage(MESSAGE_READ, bytes, -1, buffer)
                        .sendToTarget();
            } catch (IOException e) {
                break;
            }
        }
    }

    /**
     * 向藍芽模組發射資料
     *
     * @param bytes
     */
    public void write(byte[] bytes) {
        try {
            mOutStream.write(bytes);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 關閉Socket的連線
     */
    public void cancel() {
        try {
            mSocket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

藍芽在傳送資料時有大小限制,一般為20位元組,在6.0之後的版本可以進行設定大小。
如果有不正確的地方,可以在下面評論一起學習。



作者:Jarly_Sun
連結:https://www.jianshu.com/p/d9c04719052b
來源:簡書
簡書著作權歸作者所有,任何形式的轉載都請聯絡作者獲得授權並註明出處。