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

相关文章
相关标签/搜索