Android Bluetooth Profile通訊

.Bond,Bond即設備之間綁定(配對),這是藍牙設備之間通訊的基礎。當搜索到須要bond的設備時,獲取到設備對應的BluetoothDevice對象時,咱們就能夠進行bond操做了。查看BluetoothDevice源碼,在其方法中能夠找到一個叫「createBond()」方法,該方法便是藍牙bond的核心方法,但須要注意的是,該方法在API19以前是@hide的,因此minSdk設置小於API19時,須要經過反射來調用該方法android

 /**
     * Start the bonding (pairing) process with the remote device.
     * <p>This is an asynchronous call, it will return immediately. Register
     * for {@link #ACTION_BOND_STATE_CHANGED} intents to be notified when
     * the bonding process completes, and its result.
     * <p>Android system services will handle the necessary user interactions
     * to confirm and complete the bonding process.
     * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
     *
     * @return false on immediate error, true if bonding will begin
     */
    @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
    public boolean createBond() {
        if (sService == null) {
            Log.e(TAG, "BT not enabled. Cannot create bond to Remote Device");
            return false;
        }
        try {
            return sService.createBond(this, TRANSPORT_AUTO);
        } catch (RemoteException e) {Log.e(TAG, "", e);}
        return false;
    }


經過查看源碼,不難看出,createBond方法在執行時,調用了IPC,須要瞭解具體實現過程的,能夠去查看「sService 」這個IPC類的源碼,這裏就再也不深刻。
1
2.Profile,Profile是藍牙的一個很重要特性,Profile定義了設備如何實現一種鏈接或者應用,你能夠把Profile理解爲鏈接層或者應用層協。 
關於藍牙Profile的介紹能夠看這裏: 
下面來介紹Profile的鏈接: 
在android framework層中,Profile一樣是封裝成了一個個IPC類,在BluetoothAdapter中提供了」getProfileProxy(Context context, BluetoothProfile.ServiceListener listener, int profile)」方法鏈接IPC實例獲取到這些Profile服務的代理來操做這些profile以及」closeProfileProxy(int profile, BluetoothProfile profile)」來關閉這些Profile的代理ios

/**
     * Get the profile proxy object associated with the profile.
     *
     * <p>Profile can be one of {@link BluetoothProfile#HEALTH}, {@link BluetoothProfile#HEADSET},
     * {@link BluetoothProfile#A2DP}, {@link BluetoothProfile#GATT}, or
     * {@link BluetoothProfile#GATT_SERVER}. Clients must implement
     * {@link BluetoothProfile.ServiceListener} to get notified of
     * the connection status and to get the proxy object.
     *
     * @param context Context of the application
     * @param listener The service Listener for connection callbacks.
     * @param profile The Bluetooth profile; either {@link BluetoothProfile#HEALTH},
     *                {@link BluetoothProfile#HEADSET}, {@link BluetoothProfile#A2DP}.
     *                {@link BluetoothProfile#GATT} or {@link BluetoothProfile#GATT_SERVER}.
     * @return true on success, false on error
     */
    public boolean getProfileProxy(Context context, BluetoothProfile.ServiceListener listener,
                                   int profile) {
        if (context == null || listener == null) return false;git

        if (profile == BluetoothProfile.HEADSET) {
            BluetoothHeadset headset = new BluetoothHeadset(context, listener);
            return true;
        } else if (profile == BluetoothProfile.A2DP) {
            BluetoothA2dp a2dp = new BluetoothA2dp(context, listener);
            return true;
        } else if (profile == BluetoothProfile.A2DP_SINK) {
            BluetoothA2dpSink a2dpSink = new BluetoothA2dpSink(context, listener);
            return true;
        } else if (profile == BluetoothProfile.AVRCP_CONTROLLER) {
            BluetoothAvrcpController avrcp = new BluetoothAvrcpController(context, listener);
            return true;
        } else if (profile == BluetoothProfile.INPUT_DEVICE) {
            BluetoothInputDevice iDev = new BluetoothInputDevice(context, listener);
            return true;
        } else if (profile == BluetoothProfile.PAN) {
            BluetoothPan pan = new BluetoothPan(context, listener);
            return true;
        } else if (profile == BluetoothProfile.HEALTH) {
            BluetoothHealth health = new BluetoothHealth(context, listener);
            return true;
        } else if (profile == BluetoothProfile.MAP) {
            BluetoothMap map = new BluetoothMap(context, listener);
            return true;
        } else if (profile == BluetoothProfile.HEADSET_CLIENT) {
            BluetoothHeadsetClient headsetClient = new BluetoothHeadsetClient(context, listener);
            return true;
        } else if (profile == BluetoothProfile.SAP) {
            BluetoothSap sap = new BluetoothSap(context, listener);
            return true;
        } else {
            return false;
        }
    }

該方法支持鏈接HEADSET、A2DP、A2DP_SINK、AVRCP、INPUT_DEVICE、PAN、HEALTH、MAP、HEADSET_CLIENT、SAP等相應的Profile。
參數中,BluetoothProfile.SearchListener是對外用來監聽是否成功鏈接Profile的IPC實例的,與普通AIDL用來監聽鏈接的ServiceConnection相似,當「onServiceConnected(int profile, BluetoothProfile proxy)」被調用時,咱們就能夠獲取到該Profile的IPC實例來作咱們想作的事情。github

這裏已Headset來說解Profile鏈接設備的方式,其實上述這些Profile的鏈接方式都大同小異。在上面方法中,當獲取HEADSET Profile時,生成了一個BluetoothHeadset對象,該對象便是Headset IPC的代理,在該類中有"connect(BluetoothDevice device)"、"disconnect(BluetoothDevice device)"方法來鏈接和斷開與設備的Profile連接等。

/**
     * Initiate connection to a profile of the remote bluetooth device.
     *
     * <p> Currently, the system supports only 1 connection to the
     * headset/handsfree profile. The API will automatically disconnect connected
     * devices before connecting.
     *
     * <p> This API returns false in scenarios like the profile on the
     * device is already connected or Bluetooth is not turned on.
     * When this API returns true, it is guaranteed that
     * connection state intent for the profile will be broadcasted with
     * the state. Users can get the connection state of the profile
     * from this intent.
     *
     * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
     * permission.
     *
     * @param device Remote Bluetooth Device
     * @return false on immediate error,
     *               true otherwise
     * @hide
     */
    public boolean connect(BluetoothDevice device) {
        if (DBG) log("connect(" + device + ")");
        if (mService != null && isEnabled() &&
            isValidDevice(device)) {
            try {
                return mService.connect(device);
            } catch (RemoteException e) {
                Log.e(TAG, Log.getStackTraceString(new Throwable()));
                return false;
            }
        }
        if (mService == null) Log.w(TAG, "Proxy not attached to service");
        return false;
    }app

    /**
     * Initiate disconnection from a profile
     *
     * <p> This API will return false in scenarios like the profile on the
     * Bluetooth device is not in connected state etc. When this API returns,
     * true, it is guaranteed that the connection state change
     * intent will be broadcasted with the state. Users can get the
     * disconnection state of the profile from this intent.
     *
     * <p> If the disconnection is initiated by a remote device, the state
     * will transition from {@link #STATE_CONNECTED} to
     * {@link #STATE_DISCONNECTED}. If the disconnect is initiated by the
     * host (local) device the state will transition from
     * {@link #STATE_CONNECTED} to state {@link #STATE_DISCONNECTING} to
     * state {@link #STATE_DISCONNECTED}. The transition to
     * {@link #STATE_DISCONNECTING} can be used to distinguish between the
     * two scenarios.
     *
     * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
     * permission.
     *
     * @param device Remote Bluetooth Device
     * @return false on immediate error,
     *               true otherwise
     * @hide
     */
    public boolean disconnect(BluetoothDevice device) {
        if (DBG) log("disconnect(" + device + ")");
        if (mService != null && isEnabled() &&
            isValidDevice(device)) {
            try {
                return mService.disconnect(device);
            } catch (RemoteException e) {
              Log.e(TAG, Log.getStackTraceString(new Throwable()));
              return false;
            }
        }
        if (mService == null) Log.w(TAG, "Proxy not attached to service");
        return false;
    }

源碼中都有很是詳細的方法介紹,這裏就再也不敖訴。async

關於鏈接藍牙Profile的例子,能夠參考這裏:

3.Socket,綁定後的藍牙設備之間是能夠創建Socket通訊的,這種Socket相似於TCP Socket,但略有不一樣,該Socket只能經過調用Android API來獲取並鏈接,但通訊操做是與TCP相同的,能夠獲取InputStream以及OutputStream來實現數據的交互。在藍牙規範中,有個SPP(全稱Serial Port Profile) Profile,定義瞭如何在兩臺藍牙設備之間創建虛擬串口並進行鏈接,顧名思義,就是來支持藍牙設備之間的Socket通訊。該Profile在藍牙設備綁定以後便會鏈接,因此咱們只需在藍牙綁定成功後,經過調用相應的API,便可獲取BluetoothSocket對象,在該對象中提供了」getInputStream」、」getOutputStream」來獲取輸入輸出流,而後便可經過IO流來傳輸數據,實現設備通信。ide

通常的,咱們經過鏈接該Socket來實現手機控制智能設備的功能,可是Socket也僅僅只能用來數據通信,要想實現免提電話、聽音樂、外接鍵盤等功能,仍是須要去鏈接對應的Profile。
1
下面附上本身作的一個小Demo:https://github.com/Joy-Whale/BluetoothProfile
 ui

相關文章
相關標籤/搜索