美文网首页Android开发Android技术知识Android开发经验谈
【转】Android BLE4.+ 蓝牙开发国产手机兼容性解决方

【转】Android BLE4.+ 蓝牙开发国产手机兼容性解决方

作者: 紫豪 | 来源:发表于2018-09-26 14:20 被阅读11次

    本文转自冼东芝的文章Android BLE4.+ 蓝牙开发国产手机兼容性解决方案
    如有版权问题,请私信,谢谢。
    转载请注明出处。https://blog.csdn.net/u014418171/article/details/81219297

    算是做了n年的智能穿戴BLE开发了, 首先对国内的安卓开发者提醒下 , BLE开发是真的很坑, 特别是安卓, ios端也坑, 但没安卓坑 因为国产有很多手机 各种奇葩兼容都有,
    其实这些方案我很早就写到云笔记里了,一直没公开, 这里的解决方案大部分都是网上搜不到 或者网上搜到类似的问题, 但回复基本上是回答[无法解决] 或 [重启手机解决]等 没意义的解决办法,让我很无语…

    以下内容可能涉及到各种系统类源码
    你可以通过这里阅读 https://www.androidos.net.cn/

    废话不多说, 希望对你们有用


    一.刷新蓝牙app的状态

    问题描述:

    某些手机用久了会出现扫描不到任何设备的bug,
    此时是因为手机误认为本app不是[ble类] app , f**k!!!!! 还有这种操作???
    但值得注意的是, 这只是一种原因,[ 扫描不到任何设备的bug] 有很多种原因, 详情请看第3点

    解决方案:

    [目前网上没有与我类似的解决办法, 所以具体副作用自测]
    参考IBluetoothManager.aidl系统源码

    出现该问题时于是通过查看系统源码找到isBleAppPresent方法 ,反射调用其后居然返回false ,
    换了一台能正常使用的手机 调用该方法 返回true 因此证实了这个问题,
    然后发现系统有私有的updateBleAppCount方法, 可以刷新ble类app的状态,反射调用之…
    因此解决了 [偶尔ble设备扫描不出来]的bug),
    通过传入你的app包名 以 刷新 蓝牙app的错误状态

     public static void refreshBleAppFromSystem(Context context, String packageName) {
            //6.0以上才有该功能,不是6.0以上就算了
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
                return;
            }
    
            BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
            if (adapter == null) {
                return;
            }
            if (!adapter.isEnabled()) {
                return;
            }
            try {
                Object mIBluetoothManager = getIBluetoothManager(adapter);
                Method isBleAppPresentM = mIBluetoothManager.getClass().getDeclaredMethod("isBleAppPresent");
                isBleAppPresentM.setAccessible(true);
                boolean isBleAppPresent = (Boolean) isBleAppPresentM.invoke(mIBluetoothManager);
                if (isBleAppPresent) {
                    return;
                }
                Field mIBinder = BluetoothAdapter.class.getDeclaredField("mToken");
                mIBinder.setAccessible(true);
                Object mToken = mIBinder.get(adapter);
    
                //刷新偶尔系统无故把app视为非 BLE应用 的错误标识 导致无法扫描设备
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                    //8.0+ (部分手机是7.1.2 也是如此)
                    Method updateBleAppCount = mIBluetoothManager.getClass().getDeclaredMethod("updateBleAppCount", IBinder.class, boolean.class, String.class);
                    updateBleAppCount.setAccessible(true);
                    //关一下 再开
                    updateBleAppCount.invoke(mIBluetoothManager, mToken, false, packageName);
                    updateBleAppCount.invoke(mIBluetoothManager, mToken, true, packageName);
    
                } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
    
                    try {
                        //6.0~7.1.1
    
                        Method updateBleAppCount = mIBluetoothManager.getClass().getDeclaredMethod("updateBleAppCount", IBinder.class, boolean.class);
                        updateBleAppCount.setAccessible(true);
                        //关一下 再开
                        updateBleAppCount.invoke(mIBluetoothManager, mToken, false);
                        updateBleAppCount.invoke(mIBluetoothManager, mToken, true);
                    } catch (NoSuchMethodException e) {
                        //8.0+ (部分手机是7.1.2 也是如此)
                        try {
                            Method updateBleAppCount = mIBluetoothManager.getClass().getDeclaredMethod("updateBleAppCount", IBinder.class, boolean.class, String.class);
                            updateBleAppCount.setAccessible(true);
                            //关一下 再开
                            updateBleAppCount.invoke(mIBluetoothManager, mToken, false, packageName);
                            updateBleAppCount.invoke(mIBluetoothManager, mToken, true, packageName);
                        } catch (NoSuchMethodException e1) {
                            e1.printStackTrace();
                        }
                    }
                }
            } catch (Throwable e) {
                e.printStackTrace();
            }
        }
    

    二.明明gatt.disconnect() 断开蓝牙了,甚至关闭了手机的蓝牙,甚至飞行模式了, 设备仍然在 [已连接] 状态!!! 设备离手机远了才断开,说明,这压根就没断开啊!

    看到标题知道国产手机奇葩了吧? 而且我相信不少人都遇到这个问题, 这个问题经常出现在华为>小米>魅族>(VIVO|OPPO) 上。

    问题描述

    首先导致这个原因可能是:

    • 操作:
      gatt.disconnect/connect断开,连接,断开,连接,断开… 反复重试n次, 有一定的几率导致系统残留了该gatt的引用, app这边没有拿到这个引用 (app操作蓝牙api是通过 remote aidl 操作远程的 系统service ), 系统蓝牙app 也没有了这个引用 ,于是即使你 直接关闭手机蓝牙, 也没有断开连接… 有些手机直到开启飞行模式 才会断开, 而有些手机 即使开启飞行模式也不会断开! 这得看这些手机 的 飞行模式 的实现代码的区别了,暂时没去研究.
    • 猜测连接设备后 被系统杀掉/ 或手动杀掉 也会导致这种情况

    解决方案

    1.首先你可以获取真正的连接状态:

    [目前网上没有与我类似的解决办法, 所以具体副作用自测]
    参看IBluetooth.aidl系统源码
    出现这种假断开问题时, 笔者曾经尝试 各种gatt.getConnectionState(),BluetoothManager.getConnectionState都是 给我们开发者返回 已断开!, 但实际上没有断开, 经过一番研究后 发现 判断内部连接状态可以通过另一个办法 而不通过 gatt,
    BluetoothDevice类 内部的isConnected()方法
    这个方法被标记为@SystemApi@hide, 不能直接使用.
    并且在低版本的手机上没有, 查看了源码isConnected是由IBluetooth.getConnectionState()实现的, 低版本有getConnectionState

        @SystemApi
        public boolean isConnected() {
            final IBluetooth service = sService;
            if (service == null) {
                // BT is not enabled, we cannot be connected.
                return false;
            }
            try {
                return service.getConnectionState(this) != CONNECTION_STATE_DISCONNECTED;
            } catch (RemoteException e) {
                Log.e(TAG, "", e);
                return false;
            }
        }
    

    于是我们可以通过反射
    BluetoothDevice.isConnected/ IBluetooth .getConnectionState实现内部连接状态的判断
    高低版本兼容的代码如下:

    public static final int CONNECTION_STATE_DISCONNECTED = 0;
    public static final int CONNECTION_STATE_CONNECTED = 1;
    public static final int CONNECTION_STATE_UN_SUPPORT = -1;
    
        @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
        @SuppressLint("PrivateApi")
        public static int getInternalConnectionState(String mac) {
            //该功能是在21 (5.1.0)以上才支持, 5.0 以及以下 都 不支持
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
                return CONNECTION_STATE_UN_SUPPORT;
            }
            if(Build.MANUFACTURER.equalsIgnoreCase("OPPO")){//OPPO勿使用这种办法判断, OPPO无解
                return CONNECTION_STATE_UN_SUPPORT;
            }
            BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
            BluetoothDevice remoteDevice = adapter.getRemoteDevice(mac);
            Object mIBluetooth = null;
            try {
                Field sService = BluetoothDevice.class.getDeclaredField("sService");
                sService.setAccessible(true);
                mIBluetooth = sService.get(null);
            } catch (Exception e) {
                return CONNECTION_STATE_UN_SUPPORT;
            }
            if (mIBluetooth == null) return CONNECTION_STATE_UN_SUPPORT;
    
            boolean isConnected;
            try {
                Method isConnectedMethod = BluetoothDevice.class.getDeclaredMethod("isConnected");
                isConnectedMethod.setAccessible(true);
                isConnected = (Boolean) isConnectedMethod.invoke(remoteDevice);
                isConnectedMethod.setAccessible(false);
            } catch (Exception e) {
            //如果找不到,说明不兼容isConnected, 尝试去使用getConnectionState 判断
                try {
                    Method getConnectionState = mIBluetooth.getClass().getDeclaredMethod("getConnectionState", BluetoothDevice.class);
                    getConnectionState.setAccessible(true);
                    int state = (Integer) getConnectionState.invoke(mIBluetooth, remoteDevice);
                    getConnectionState.setAccessible(false);
                    isConnected = state == CONNECTION_STATE_CONNECTED;
                } catch (Exception e1) {
                    return CONNECTION_STATE_UN_SUPPORT;
                }
            }
            return isConnected ? CONNECTION_STATE_CONNECTED : CONNECTION_STATE_DISCONNECTED;
    
        }
    

    2.尝试断开

    [目前网上没有与我类似的解决办法, 所以具体副作用自测]
    参考AdapterService.java系统源码
    仍然是从IBluetooth入手, 因为 应用层 能拿到的东西不多
    研究源码发现 有两个函数可以尝试让 ble 服务关闭和启动,分别是onLeServiceUp / onBrEdrDown
    示例:

        @RequiresApi(api = Build.VERSION_CODES.M)
        public static void setLeServiceEnable(boolean isEnable) {
    
            Object mIBluetooth;
            try {
                Field sService = BluetoothDevice.class.getDeclaredField("sService");
                sService.setAccessible(true);
                mIBluetooth = sService.get(null);
            } catch (Exception e) {
                return;
            }
            if (mIBluetooth == null) return;
    
            try {
                if (isEnable) {
                    Method onLeServiceUp = mIBluetooth.getClass().getDeclaredMethod("onLeServiceUp");
                    onLeServiceUp.setAccessible(true);
                    onLeServiceUp.invoke(mIBluetooth);
                } else {
                    Method onLeServiceUp = mIBluetooth.getClass().getDeclaredMethod("onBrEdrDown");
                    onLeServiceUp.setAccessible(true);
                    onLeServiceUp.invoke(mIBluetooth);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    

    但该方法可能在某些手机上仍然无效,原因是 很多国产手机都重新修改了 蓝牙底层相关代码, 为了所谓的省电, 所以单靠看原生系统的源码可能是无意义的
    之后琢磨出另一个解决办法 那就是…. 尝试连接~然后断开!
    方法很简单,直接通过gatt.connectGatt()等待连接成功后disconnect一次, 此时设备终于断开了!
    原因可能是connect后 刷新了残留的gatt引用 于是app又重新拿到了最新的引用, 此时可以操作设备断开了

    ...
    gatt.connectGatt();
    ...
    onConnectionStateChange(final BluetoothGatt gatt, final int status, int newState){
           if (newState == BluetoothProfile.STATE_CONNECTED){
              gatt.disconnect();
           }
    }
    

    不过你要注意下不要和你的正常连接逻辑冲突

    以上操作,手机显示的蓝牙图标一直是关闭的, 你可能想问我 : 那手机蓝牙关了 怎么反射让他显示开… 这个你只能问这个手机的相关工程师为啥这么脑残了… 无解, 我们只考虑app问题,系统脑残管不了


    三.多次打开app/退出app/后台被杀等, 导致扫描不到设备,并返回ScanCallback.SCAN_FAILED_APPLICATION_REGISTRATION_FAILED 错误!

    问题描述

    但值得注意的是, 这只是第二种原因,[ 扫描不到任何设备的bug]还有其他原因, 详情请看第4点
    扫描周围的BLE设备时某些手机会遇到 GATT_Register: cant Register GATT client, MAX client reached!
    或者回调中的 onScanFailed 返回了 errorCode =2 则: ScanCallback.SCAN_FAILED_APPLICATION_REGISTRATION_FAILED
    具体表现则为 明明周围有很多设备,但是扫描不到任何东西
    查到
    1.https://blog.csdn.net/chy555chy/article/details/53788748
    2.https://stackoverflow.com/questions/27516399/solution-for-ble-scans-scan-failed-application-registration-fail
    3.http://detercode121.blogspot.com/2012/04/bluetooth-lowenergy-solution-for-ble.html
    等等 没有一个是正常的解决办法,上面这些修复方案是用代码实现关闭蓝牙然后重新打开蓝牙来释放 可是 国产的手机会弹出蓝牙授权的 比如我们要后台扫描重连设备时遇到这种情况 难道要弹出授权让用户确定? 那还要后台重连功能干啥…
    而且,有些手机即使关闭蓝牙再打开 也无法释放,有些手机关闭蓝牙后 再打开会卡死系统, 导致蓝牙图标一直卡在那很久 才打开了蓝牙…

    解决方案

    [目前网上没有与我类似的解决办法, 所以具体副作用自测]

    参考IBluetoothGatt.aidl
    参考BluetoothLeScanner.java
    参考ScanManager.java
    参考GattService.java

    问题就在于 一些手机在startScan扫描的过程中还没来得及stopScan,就被系统强制杀掉了, 导致mClientIf未被正常释放,实例和相关蓝牙对象已被残留到系统蓝牙服务中,
    打开app后又重新初始化ScanCallback多次被注册,导致每次的扫描mClientIf的值都在递增, 于是mClientIf的值
    在增加到一定程度时(最大mClientIf数量视国产系统而定 不做深究),onScanFailed返回了errorCode =2至今网上无任何正常的解决办法
    于是 我查看了系统源码 发现关键位置BluetoothLeScanner类下的 BleScanCallbackWrapper#startRegistration()扫描是通过registerClient传入 mClientIf 来实现的,
    stopScan时调用了iGatt.stopScan()iGatt.unregisterClient()进行解除注册. 了解该原理后 我们就可以反射调用这个方法 , 至于解除mClientIf哪个值 需要你自己做存储记录
    这里我写的是解除全部客户端 mClientIf的范围是 0~40
    问题至此完美解决 这可能是目前全网唯一不用关闭/开启蓝牙就能完美解决该问题的方案

     public static boolean releaseAllScanClient() {
            try {
                Object mIBluetoothManager = getIBluetoothManager(BluetoothAdapter.getDefaultAdapter());
                if (mIBluetoothManager == null) return false;
                Object iGatt = getIBluetoothGatt(mIBluetoothManager);
                if (iGatt == null) return false;
    
                Method unregisterClient = getDeclaredMethod(iGatt, "unregisterClient", int.class);
                Method stopScan;
                int type;
                try {
                    type = 0;
                    stopScan = getDeclaredMethod(iGatt, "stopScan", int.class, boolean.class);
                } catch (Exception e) {
                    type = 1;
                    stopScan = getDeclaredMethod(iGatt, "stopScan", int.class);
                }
    
                for (int mClientIf = 0; mClientIf <= 40; mClientIf++) {
                    if (type == 0) {
                        try {
                            stopScan.invoke(iGatt, mClientIf, false);
                        } catch (Exception ignored) {
                        }
                    }
                    if (type == 1) {
                        try {
                            stopScan.invoke(iGatt, mClientIf);
                        } catch (Exception ignored) {
                        }
                    }
                    try {
                        unregisterClient.invoke(iGatt, mClientIf);
                    } catch (Exception ignored) {
                    }
                }
                stopScan.setAccessible(false);
                unregisterClient.setAccessible(false);
                BLESupport.getDeclaredMethod(iGatt, "unregAll").invoke(iGatt);
                return true;
            } catch (Exception e) {
                e.printStackTrace();
            }
            return false;
        }
    

    其中如果你想获得 mClientIf 的值,方便研究该问题 可以尝参考以下代码
    其中参数ScanCallback类 是安卓6.0扫描回调类

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
        public static boolean isScanClientInitialize(ScanCallback callback) {
            try {
                Field mLeScanClientsField = getDeclaredField(BluetoothLeScanner.class, "mLeScanClients");
                //  HashMap<ScanCallback, BleScanCallbackWrapper>()
                HashMap callbackList = (HashMap) mLeScanClientsField.get(BluetoothAdapter.getDefaultAdapter().getBluetoothLeScanner());
                int size = callbackList == null ? 0 : callbackList.size();
                if (size > 0) {
                    Iterator iterator = callbackList.entrySet().iterator();
                    while (iterator.hasNext()) {
                        Map.Entry entry = (Map.Entry) iterator.next();
                        Object key = entry.getKey();
                        Object val = entry.getValue();
                        if (val != null && key != null && key == callback) {
                            int mClientIf = 0;
                            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                                Field mScannerIdField = getDeclaredField(val, "mScannerId");
                                mClientIf = mScannerIdField.getInt(val);
    
                            } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                                Field mClientIfField = getDeclaredField(val, "mClientIf");
                                mClientIf = mClientIfField.getInt(val);
                            }
                            System.out.println("mClientIf=" + mClientIf);
                            return true;
                        }
                    }
                } else {
                    if (callback != null) {
                        return false;
                    }
                }
    
    
            } catch (Exception ignored) {
    
            }
    
            return true;
        }
    

    四、扫描不到设备

    前面说了好几个扫描不到设备的原因, 这里还有呢…
    1.未开启位置访问权限Manifest.permission.ACCESS_COARSE_LOCATION如果你是6.0系统 则需要申请该权限 才能扫描设备, 检查和申请网上有 这里不重复说了
    2.检查GPS的 LOCATION_MODE是否开启,否则在OPPO/VIVO等手机 无法扫描设备。

    //代码 反编译 nrfconnect 参考得来:
    public static boolean hasLocationEnablePermission(Context context) {
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
                return true;
            }
            int locationMode = Settings.Secure.LOCATION_MODE_OFF;
            try {
                locationMode = Settings.Secure.getInt(context.getContentResolver(), Settings.Secure.LOCATION_MODE);
            } catch (Exception ignored) {
            }
            if (locationMode != Settings.Secure.LOCATION_MODE_OFF) {
                return true;
            }
            return false;
    }
    //没有权限则跳转到 gps界面授权
    if(!hasLocationEnablePermission(this)){
      Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
      intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
      context.startActivity(intent);
    }
    

    3.安卓7.0不允许在30s内连续扫描5次,否则无法扫描到任何设备,只能重启app, 你可以写一个算法 比如每次先延时30/5=6秒 才开始扫描, 以防止用户一直点扫描按钮 , 或者使用动态计算 以减少用户等待时间


    五、其他注意点

    1.为了加快连接设备的速度 , 你可以不扫描设备直接通过mac地址连接 ,使用 gatt.connectGatt ,但有时候连接不上是因为 设备信息可能变化了, 但系统缓存没变,所以一直连接不上, 即使连接上了 马上返回各种-133 -192等错误, 解决办法是 你需要 重新扫描这个mac一下,找到了mac ,再连接

    2.扫描设备的时候 要切记, 扫描到了后 先停止扫描, 过1秒左右 再连接, 避免扫描的时候连接, 导致连接过程中 缓存再次被刷新

    3.无任何原因, app扫描不到该设备,但能搜索到其他设备, 而另一个手机却都能搜索到, 试试下载 nrf的 nrfconnect 去搜索测试(同一台手机), 若 nrfconnect 能搜索到 则是app代码问题, 否则检测 设备蓝牙晶振频率 是否不支持该手机的蓝牙频率发现范围! 联系相关开发人员解决

    4.距离防丢功能, 通过rssi可以拿到设备距离手机的信号值来判断 设备是否远离手机 触发防丢警报, 但rssi信号 受各种环境因素影响, 所以有点坑 , 建议做延迟处理 ,意思是达到防丢rssi值时 延时n秒 才警报, 若在n秒内 又恢复, 说明只是信号突然弱了一下. 无需 警报. 还有就是因素太多了 ,和手机的蓝牙模块有关, 和设备的蓝牙天线有关, 功率有关等, 建议在app内添加 一个用户可以设定的rssi防丢范围, 因为程序没法精准计算

    5.扫描蓝牙设备callback回调时 建议丢到另外一个线程用队列去处理, 不要在扫描回调里处理耗时逻辑., 同理 在onCharacteristicChanged 中接收设备notify通知返回的数据时, 不要在此方法内进行耗时处理, 否则大量数据过来时会100%丢包!!! 解决办法和前面的一样. (话说某BLE开源框架就有这个问题,还好我用我自己写的)

    6.同步大量数据时, 某些手机完美正常, 某些手机出现丢包严重,建议修改连接间隔 同步前 使用gatt.requestConnectionPriority(CONNECTION_PRIORITY_HIGH) , 同步完成后 恢复原来的连接间隔CONNECTION_PRIORITY_BALANCED

    7.对设备进行OTA升级后,直接使用mac来连接, 连接不上, 原因是系统缓存没刷新, 你需要扫描后停止扫描再连接

    8.连接之前建议先把 gatt.close一下

    9.使用gatt.discoverServices()发现服务之前,建议先 sleep 500 毫秒, 因为刚刚连接上, 系统有些东西需要刷新,同理,遇到任何问题 延时一下看看能否解决, 因为有些系统的蓝牙很慢很卡,甚至手动关闭蓝牙 都卡死在那 ,偶尔还死机重启了…


    六、补充

    贴出一些上面缺失的函数,因为方便和减少代码重复量, 所以上面没贴

        @SuppressLint("PrivateApi")
        public static Object getIBluetoothGatt(Object mIBluetoothManager) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
            Method getBluetoothGatt = getDeclaredMethod(mIBluetoothManager, "getBluetoothGatt");
            return getBluetoothGatt.invoke(mIBluetoothManager);
        }
    
    
        @SuppressLint("PrivateApi")
        public static Object getIBluetoothManager(BluetoothAdapter adapter) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
            Method getBluetoothManager = getDeclaredMethod(BluetoothAdapter.class, "getBluetoothManager");
            return getBluetoothManager.invoke(adapter);
        }
    
    
        public static Field getDeclaredField(Class<?> clazz, String name) throws NoSuchFieldException {
            Field declaredField = clazz.getDeclaredField(name);
            declaredField.setAccessible(true);
            return declaredField;
        }
    
    
        public static Method getDeclaredMethod(Class<?> clazz, String name, Class<?>... parameterTypes) throws NoSuchMethodException {
            Method declaredMethod = clazz.getDeclaredMethod(name, parameterTypes);
            declaredMethod.setAccessible(true);
            return declaredMethod;
        }
    
    
        public static Field getDeclaredField(Object obj, String name) throws NoSuchFieldException {
            Field declaredField = obj.getClass().getDeclaredField(name);
            declaredField.setAccessible(true);
            return declaredField;
        }
    
    
        public static Method getDeclaredMethod(Object obj, String name, Class<?>... parameterTypes) throws NoSuchMethodException {
            Method declaredMethod = obj.getClass().getDeclaredMethod(name, parameterTypes);
            declaredMethod.setAccessible(true);
            return declaredMethod;
        }
    

    你可能还想问, 还有呢 还有最重要的 连接时总是返回 -133 -86 -192 这些怎么办啊 怎么解决啊
    我只想和你说, 别抱着希望了 你可能在网上看到很多解决办法 但最终你使用了解决代码, 仍然无法解决…
    放弃吧, 换一种思路, 遇到这种错误, 直接断开+sleep+扫描+重连, , 若检测到无数次返回这种错误,没一次连接成功的情况 记录下次数, 达到一定数量时 提示让用户关闭/开启飞行模式 然后重试吧. 这种因素很多 有手机蓝牙辣鸡的,有代码有问题的比如不扫描就连接, 有蓝牙设备有问题的 各种因素都有.


    七、调试

    调试设备的工具 有 ios的lightblue,
    安卓的推荐nrf芯片公司开发的 nrf connect 调试工具]

    我也写了两个小应用,有兴趣可以下来看看
    BLE调试器
    https://www.coolapk.com/apk/com.toshiba.ble
    BLE指令协议窃取工具(需要xposed), 可以窃取手机上的某app和其对应的ble设备 正在进行的数据通讯, 你可以理解为蓝牙协议抓包 (仅供学习用途)
    https://www.coolapk.com/apk/com.tos.bledetector


    拓展阅读

    android ble常见问题收集


    如果您有更好的建议欢迎评论分享,如有错误,请批评指正,谢谢。

    相关文章

      网友评论

        本文标题:【转】Android BLE4.+ 蓝牙开发国产手机兼容性解决方

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