Android代码封装

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

2020-05-08  本文已影响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;
    }
}
上一篇 下一篇

猜你喜欢

热点阅读