美文网首页Android代码封装
Android 蓝牙实现自动配对方案代码 避免手动输入

Android 蓝牙实现自动配对方案代码 避免手动输入

作者: 极客大白 | 来源:发表于2020-05-08 17:58 被阅读0次

    最近工作中遇到一个蓝牙自动完成配对的问题,感觉比较好玩,尝试了一下,成功了,简单说一下。

    原理

    通过反射调用BluetoothDevice的相关方法,实现避免手动输入pin(配对码).

    限制

    所谓Android 蓝牙自动配对,并不能在所有场景实现,说一下限制:

    1、Android8.0以上版本手机,由于Google对反射做了限制,无法实现;
    2、厂商限制,华为手机,华为应该对蓝牙部分做了特殊处理,该方法在华为设备上无效;

    低版本可以自己玩一玩,高版本基本没戏了,除非root。

    Talk is cheep show the code:

    代码如下:

        <application
            android:name=".MyApplication"
            android:icon="@mipmap/ic_logo"
            android:label="@string/app_name"
            android:roundIcon="@mipmap/ic_logo"
            android:supportsRtl="true"
            android:theme="@style/AppTheme">
    
            <receiver android:name=".ble.receiver.BleAutoPairReceiver" >
                <intent-filter android:priority="1000">
                    <action android:name="android.bluetooth.device.action.PAIRING_REQUEST"/>
                    <action android:name="android.bluetooth.device.action.FOUND" />
                </intent-filter>
            </receiver>
    
        </application>
    
    public class BleAutoPairReceiver extends BroadcastReceiver {
    
        /**
         * 目标蓝牙设备mac
         */
        private static String sAimedBluetoothDeviceMac = "";
    
        /**
         * 配对所用的配对码
         */
        private static String sCurrentPin = "";
    
        public BleAutoPairReceiver() {
        }
    
        @Override
        public void onReceive(Context context, Intent intent) {
    
            String action = intent.getAction();
            LogUtil.i("ble_action=" + action);
            BluetoothDevice bluetoothDevice = null;
            // 从Intent中获取设备对象
            bluetoothDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
    
    
            if (isAimedDevice(bluetoothDevice)) {
    
    
                LogUtil.i("aimed_ble_device:" +
                        "[" + bluetoothDevice.getName() + "]"
                        + ":" + bluetoothDevice.getAddress());
    
                if (!BleFactoryTool.INSTANCE.isAutoPair()) {
                    LogUtil.i("ble_auto_pair_not_enabled,return");
                    return;
                }
    
                LogUtil.i("ble_auto_pair_enabled__try_auto_pair");
    
                switch (action) {
                    case BluetoothDevice.ACTION_FOUND:
                        //发现设备
                        if (bluetoothDevice.getBondState() == BluetoothDevice.BOND_NONE) {
                            boolean isCreateBondSuccess = BleAutoPairHelper.createBond(bluetoothDevice);
                            LogUtil.i("try to bond:isCreateBondSuccess=" + isCreateBondSuccess);
                        }
    
                        break;
                    case BluetoothDevice.ACTION_PAIRING_REQUEST:
                        // 设备处于待配对状态
    
                        //1.确认配对
                        boolean isSetPairingConfirmationSuccess =
                                BleAutoPairHelper.setPairingConfirmation(bluetoothDevice, true);
                        LogUtil.i("isSetPairingConfirmationSuccess=" + isSetPairingConfirmationSuccess);
    
                        //2.调用setPin方法进行配对...
                        boolean isSetPinSuccess =
                                BleAutoPairHelper.setPin(bluetoothDevice, getPin());
                        LogUtil.i("isSetPinSuccess=" + isSetPinSuccess);
                        if (isSetPinSuccess) {
                            //3.终止有序广播
                            //如果没有将广播终止,则会出现一个一闪而过的配对框。
                            LogUtil.i("isSetPairingConfirmationSuccess=" + isSetPairingConfirmationSuccess);
                            abortBroadcast();
                        }
                        break;
    
                    default:
                        LogUtil.e("unsupported action=" + action);
                        break;
    
                }
    
            }
        }
    
    
        private boolean isAimedDevice(BluetoothDevice bluetoothDevice) {
            if (null == bluetoothDevice) {
                LogUtil.e("bluetoothDevice cannot be null");
                return false;
            }
    
            if (TextUtils.isEmpty(sAimedBluetoothDeviceMac)) {
                LogUtil.e("AimedBluetoothDeviceMac cannot be empty");
                return false;
            }
    
            return TextUtils.equals(getAimedDeviceMac(), bluetoothDevice.getAddress());
        }
    
        public static void setAimedBluetoothDeviceMac(String bluetoothDeviceMac) {
            LogUtil.i("setAimedBluetoothDeviceMac bluetoothDeviceMac=" + bluetoothDeviceMac);
            sAimedBluetoothDeviceMac = bluetoothDeviceMac;
        }
    
        public static void setCurrentPin(String pin) {
            LogUtil.i("setCurrentPin pin=" + pin);
            sCurrentPin = pin;
        }
    
        private String getPin() {
            return sCurrentPin;
        }
    
        private String getAimedDeviceMac() {
            return sAimedBluetoothDeviceMac;
        }
    }
    
    /**
     * 蓝牙配对辅助类
     * Android 8.0及以下版本大多数设备有效(已知华为手机除外)
     * 参考源码:platform/packages/apps/Settings.git
     * Settings/src/com/android/settings/bluetooth/CachedBluetoothDevice.java
     *
     * @date 2020/5/7
     */
    public class BleAutoPairHelper {
        private static final String TAG = "BleAutoPairHelper";
    
    
        /**
         *
         * @param bluetoothDevice
         * @return
         */
        public static boolean createBond(BluetoothDevice bluetoothDevice) {
            return invokeMethod(bluetoothDevice, "createBond");
        }
    
        /**
         * 与设备解除配对
         */
        public static boolean removeBond(BluetoothDevice bluetoothDevice) {
            return invokeMethod(bluetoothDevice, "removeBond");
        }
    
        /**
         * 设置配对码
         * @param bluetoothDevice
         * @param pinStr
         * @return
         */
        public static boolean setPin(BluetoothDevice bluetoothDevice,
                                     String pinStr) {
            byte[] pinCodeBytes = convertPinToBytes(pinStr);
            return invokeMethod(bluetoothDevice, "setPin", byte[].class, pinCodeBytes);
        }
    
        /**
         * 取消配对框
         *
         * @param bluetoothDevice
         * @return
         */
        public static boolean cancelPairingUserInput(BluetoothDevice bluetoothDevice) {
            return invokeMethod(bluetoothDevice, "cancelPairingUserInput");
    
        }
    
        /**
         * 确认配对
         *
         * @param bluetoothDevice
         * @param isConfirm
         * @return
         */
        public static boolean setPairingConfirmation(BluetoothDevice bluetoothDevice,
                                                     boolean isConfirm) {
            return invokeMethod(bluetoothDevice, "setPairingConfirmation",
                    boolean.class, isConfirm);
        }
    
        public static boolean cancelBondProcess(BluetoothDevice bluetoothDevice) {
            return invokeMethod(bluetoothDevice, "cancelBondProcess");
        }
    
    
        private static boolean invokeMethod(BluetoothDevice bluetoothDevice, String methodName) {
            return invokeMethod(bluetoothDevice, methodName, null, null);
        }
    
        private static boolean invokeMethod(BluetoothDevice bluetoothDevice,
                                            String methodName,
                                            Class<?> paramClassType,
                                            Object param) {
            if (null == bluetoothDevice) {
                LogUtil.e("bluetoothDevice can not be null");
                return false;
            }
            Class<? extends BluetoothDevice> clazz = bluetoothDevice.getClass();
            Method method = null;
    
            try {
    
    
                Boolean isSuccess = false;
                if (null == paramClassType) {
                    method = clazz.getMethod(methodName);
                    isSuccess = (Boolean) method.invoke(bluetoothDevice);
                } else {
                    method = clazz.getDeclaredMethod(methodName, paramClassType);
                    isSuccess = (Boolean) method.invoke(bluetoothDevice, param);
                }
    
                LogUtil.i(TAG
                        + " invokeMethod clazz=" + clazz.getSimpleName()
                        + " mac" + bluetoothDevice.getAddress()
                        + " methodName=" + methodName
                        + " paramType=" + paramClassType
                        + " param=" + param
                        + " isSuccess=" + isSuccess
                );
                return isSuccess;
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
                LogUtil.e("NoSuchMethodException", e);
                return false;
            } catch (IllegalAccessException e) {
                e.printStackTrace();
                LogUtil.e("IllegalAccessException", e);
                return false;
            } catch (InvocationTargetException e) {
                e.printStackTrace();
                LogUtil.e("InvocationTargetException", e);
                return false;
            }
        }
    
        /**
         * copy from android.bluetooth.BluetoothDevice
         *
         * @param pin
         * @return
         */
        private static byte[] convertPinToBytes(String pin) {
            if (pin == null) {
                return null;
            }
            byte[] pinBytes;
            try {
                pinBytes = pin.getBytes("UTF-8");
            } catch (UnsupportedEncodingException uee) {
                // this should not happen
                Log.e(TAG, "UTF-8 not supported?!?");
                return null;
            }
            if (pinBytes.length <= 0 || pinBytes.length > 16) {
                return null;
            }
            return pinBytes;
        }
    }
    

    相关文章

      网友评论

        本文标题:Android 蓝牙实现自动配对方案代码 避免手动输入

        本文链接:https://www.haomeiwen.com/subject/jdhqnhtx.html