Android中经典蓝牙的自动配对实现方法

前  言

在前面的文章《Android中经典蓝牙与低功耗蓝牙的简单对比分析》中,我们简单对比了一下当前使用的两种蓝牙技术的区别及使用方法。今天,澳门网上真人博彩就跟大家分享一下在蓝牙开发中常见的一个需求实现方法——蓝牙自动配对。

方法其实很简单,但咱们还是得了解一下经典蓝牙的一些内部实现原理。

需要说明的是,此自动配对方法仅针对有固定PIN码的设备,比如使用智能手机连接蓝牙耳机、蓝牙音箱等设备。如果两个设备都是智能手机,使用当前的方法是无法实现的(因为智能手机PIN码一般是自动生成的)。这是两种不同的应用场景,方法也不一样。下面,还是正式开始说明吧。

Android中经典蓝牙的自动配对实现方法

之前有提到,蓝牙设备的通信流程,如下:

  • 发现设备->配对/绑定设备->建立连接->数据通信

这篇,我们主要关心的就是前面两个阶段“发现设备->配对/绑定设备”。

依然还是从发现设备开始。首先要获取到 BluetoothAdapter,下面是一个通用的获取方法:

    /**
     * 功能:获取蓝牙适配器
     */
    public BluetoothAdapter getBluetoothAdapter(Context context) {
        BluetoothManager bluetoothManager = (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE);
        if (bluetoothManager == null) {
            Log.e(TAG, "Unable to initialize BluetoothManager.");
        } else {
            mBluetoothAdapter = bluetoothManager.getAdapter();
        }
        return mBluetoothAdapter;
    }

在获取了相应Context下的BluetoothAdapter对象后,就可以直接调用BluetoothAdapter的startDiscovery()方法来发现相应的蓝牙设备了。

    mBluetoothAdapter.startDiscovery();

在调用了这个 startDiscovery() 方法后,实际上就会交由 Android 内部来处理找到设备和发出相关信息的广播了。接下来只需要根据相应的广播类型,进行区分即可。

而咱们需要注册的广播类型一般有下面几种:

    private void init() {
        mContext = this;
        // 分别注册三种类型的广播接收器:
        // 1.BluetoothDevice.ACTION_FOUND —— 发现了一台蓝牙设备
        // 2.BluetoothAdapter.ACTION_DISCOVERY_FINISHED —— 扫描设备的动作完成
        // 3.BluetoothConstants.PAIRING_REQUEST —— 触发了配对请求
        // 4.BluetoothDevice.ACTION_BOND_STATE_CHANGED —— 当前的绑定状态返回
        IntentFilter foundFilter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
        mContext.registerReceiver(mReceiver, foundFilter);
        IntentFilter discoveryFilter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
        mContext.registerReceiver(mReceiver, discoveryFilter);
        IntentFilter pairFilter = new IntentFilter(BluetoothConstants.PAIRING_REQUEST);
        mContext.registerReceiver(mReceiver, pairFilter);
        IntentFilter bondFilter = new IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
        mContext.registerReceiver(mReceiver, bondFilter);
    }

其中的mReceiver的具体实现如下:

    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
			BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
            if (BluetoothDevice.ACTION_FOUND.equals(action)) { // 每发现一台蓝牙设备都会发出此广播
				Log.i("test", "发现了一台蓝牙设备!");
				// 处理获取到的蓝牙设备device,一般是将其存入一个蓝牙设备列表list
            }else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
				Log.i(TAG, "扫描蓝牙设备结束!");
				// 进行设备扫描结束的动作
            }else if (BluetoothDevice.ACTION_PAIRING_REQUEST.equals(action)) {
                Log.i(TAG, "开始设置经典蓝牙的配对PIN码!");
				String pinStr = "0000"; // 这里是你需要进行替换的已知蓝牙设备PIN码
				ClsUtils.setPin(device.getClass(), device, pinStr); // 调用工具类中设置PIN码的方法setPin()
            } else if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(action)) {
                Log.i(TAG, "蓝牙绑定状态改变!");
                switch (device.getBondState()) {
                case BluetoothDevice.BOND_BONDING:
                    Log.i(TAG, "设备正在绑定中...");
                    break;
                case BluetoothDevice.BOND_BONDED:
                    Log.i(TAG, "设备已绑定!");
                    break;
                case BluetoothDevice.BOND_NONE:
                    Log.i(TAG, "设备未绑定!");
                    break;
                }
			}
        }
    };

在新建 BroadcastReceiver 的对象 mReceiver 时,调用了一个网上流传颇广的工具类 ClsUtils,如下:

/**
 * 功能:蓝牙工具类
 */
public class ClsUtils {
    /**
     * 与设备配对
     */
    @SuppressWarnings({ "unchecked", "rawtypes" })
    public static boolean createBond(Class btClass, BluetoothDevice btDevice) throws Exception {
        Method createBondMethod = btClass.getMethod("createBond");
        Boolean returnValue = (Boolean) createBondMethod.invoke(btDevice);
        return returnValue.booleanValue();
    }

    /**
     * 与设备解除配对
     */
    @SuppressWarnings({ "unchecked", "rawtypes" })
    public static boolean removeBond(Class btClass, BluetoothDevice btDevice) throws Exception {
        Method removeBondMethod = btClass.getMethod("removeBond");
        Boolean returnValue = (Boolean) removeBondMethod.invoke(btDevice);
        return returnValue.booleanValue();
    }

    @SuppressWarnings({ "unchecked", "rawtypes" })
    public static boolean setPin(Class btClass, BluetoothDevice btDevice, String str) throws Exception {
        try {
            Method removeBondMethod = btClass.getDeclaredMethod("setPin", new Class[] { byte[].class });
            Boolean returnValue = (Boolean) removeBondMethod.invoke(btDevice, new Object[] { str.getBytes() });
            Log.e("returnValue", "" + returnValue);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return true;

    }

    /**
     * 功能:取消用户输入
     */
    @SuppressWarnings({ "unchecked", "rawtypes" })
    public static boolean cancelPairingUserInput(Class btClass, BluetoothDevice device) throws Exception {
        Method createBondMethod = btClass.getMethod("cancelPairingUserInput");
        // cancelBondProcess()
        Boolean returnValue = (Boolean) createBondMethod.invoke(device);
        return returnValue.booleanValue();
    }

    /**
     * 功能:取消配对
     */
    @SuppressWarnings({ "unchecked", "rawtypes" })
    public static boolean cancelBondProcess(Class btClass, BluetoothDevice device) throws Exception {
        Method createBondMethod = btClass.getMethod("cancelBondProcess");
        Boolean returnValue = (Boolean) createBondMethod.invoke(device);
        return returnValue.booleanValue();
    }

    @SuppressWarnings("rawtypes")
    public static void printAllInform(Class clsShow) {
        try {
            // 取得所有方法
            Method[] hideMethod = clsShow.getMethods();
            int i = 0;
            for (; i < hideMethod.length; i++) {
                Log.e("method name", hideMethod[i].getName() + ";and the i is:" + i);
            }
            // 取得所有常量
            Field[] allFields = clsShow.getFields();
            for (i = 0; i < allFields.length; i++) {
                Log.e("Field name", allFields[i].getName());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

那么,以上就基本完成了自动配对需要的处理步骤。

然后,在需要的地方调用绑定方法 ClsUtils.createBond() 就会触发广播“BluetoothDevice.ACTION_PAIRING_REQUEST”了。

如果想要知道设备的绑定状态,可以在绑定状态发生变化时进行处理,参考上面代码中 mReceiver 对接收到的“BluetoothDevice.ACTION_BOND_STATE_CHANGED”广播进行处理的示例即可。

小  结

可以看到,整个自动绑定的过程实际上就是发出广播与处理广播的过程,只不过这里不是咱们手动调用发送广播,而是调用安卓的相应方法后触发的内部广播。

需要额外说明的是,此方法还是会触发 Android 系统调用一个设置PIN码的对话框,只不过会自动消失,不影响使用。

澳门网上真人博彩在起初就因为这个自动绑定的问题被卡住了一段时间。网上虽然也有一些关于蓝牙自动配对的文章,但是写的都不是那么详细,或者说描述都不是那么清晰,看了还是有点摸不着头脑。为了防止再次出现相同的问题,这里将整个过程详细描述并分享出来供大家交流学习。如果发现有什么问题,希望各位小伙伴能够在下方评论处留下你宝贵的建议,谢谢大家啦。

您可以选择一种方式赞助本站

支付宝转账赞助

支付宝扫一扫赞助

「评论总计:9 条」「访客:5 条」「站长:4 条」

  1. avatar

    有点不懂,不过还是支持一下

  2. avatar

    博主文章不错,友链可好?
    已经加上您的了https://www.techair.cc/link.html

  3. avatar

    非常不错!!!!

  4. avatar

    你这是干啥?

评论加载中...

发表评论