Android7.1(N) Ble 开发问题汇总一

转载请标明出处:https://blog.csdn.net/lansefeiyang08/article/details/82774977

最近又重操旧业,帮忙接了一些Android系统连接Ble外设的问题,这些问题比较棘手,如果不能修改Android系统源码,修复的可能性比较小。像三星这些大厂应该是有自己的团队来解决这些问题,后面的问题汇总,仅供参考,希望能解决各位遇到的问题:

问题一:.Android系统启动BLE扫描,默认扫描时间是30分钟。

通常情况下,手机App的开发,不需要在后台运行扫描外设,通常会把扫描的启动和结束放到主界面里,如果退出主界面就会停止扫描,但是如果你在你的app里加入了一个服务,且想让app一直扫描,那么你的扫描时间最多是30分钟。为什么呢?

因为在系统源码路径/packages/apps/Bluetooth/src/com/android/bluetooth/gatt/ScanManager.java中的 handleStartScan方法里有这样一个操作:

207        void handleStartScan(ScanClient client) {
208            Utils.enforceAdminPermission(mService);
209            logd("handling starting scan");
210
211            if (!isScanSupported(client)) {
212                Log.e(TAG, "Scan settings not supported");
213                return;
214            }
215
216            if (mRegularScanClients.contains(client) || mBatchClients.contains(client)) {
217                Log.e(TAG, "Scan already started");
218                return;
219            }
220            // Begin scan operations.
221            if (isBatchClient(client)) {
222                mBatchClients.add(client);
223                mScanNative.startBatchScan(client);
224            } else {
225                mRegularScanClients.add(client);
226                mScanNative.startRegularScan(client);
227                if (!mScanNative.isOpportunisticScanClient(client)) {
228                    mScanNative.configureRegularScanParams();
229
230                    if (!mScanNative.isExemptFromScanDowngrade(client)) {
231                        Message msg = mHandler.obtainMessage(MSG_SCAN_TIMEOUT);
232                        msg.obj = client;
233                        // Only one timeout message should exist at any time
234                        mHandler.sendMessageDelayed(msg, AppScanStats.SCAN_TIMEOUT_MS);
235                    }
236                }

237
238                // Update BatteryStats with this workload.
239                try {
240                    mBatteryStats.noteBleScanStarted(client.workSource);
241                } catch (RemoteException e) {
242                    /* ignore */
243                }
244            }
245        }

第230行到第236中做了一个操作,即在启动扫描的时候,同时启动了一个Delay 30min的handle message,当30min时间到的时候会stop scan。所以如果你发现ble扫描30min就停止了,不要奇怪,因为是有人故意设置的,目的当时为了省功耗。

问题二:执行disconnect断开外设连接,但是1s内又返回onConnected消息,自动连接成功上外设。会让开发者觉得disconnect不成功。

要想解决的这个问题,首先要清楚这个是什么原因导致的。Android bluedroid机制里有一个设置,就是只要真正没有app连接ble了才会断开连接,超时时间是1s。

因为系统/system/bt/stack/include/gatt_api.h下有这样一个定义:

552#define GATT_LINK_IDLE_TIMEOUT_WHEN_NO_APP    1 /* start a idle timer for this duration
553                                                 when no application need to use the link */
   

把这个define改成0,你会发现再执行disconnect会立即断开连接,不会再在1s内收到onConnected回调。这个问题的修复就不再是App工程师可以解决的问题,必须要系统工程师去修改bluedroid的源码才可以解决。

问题三:bluetoothGatt类的connect连接有时候连接比较慢的修复方式

今天再讲最后一个问题,关于重连时间有点长甚至连接不上的问题。

大部分搞Ble的App工程师,从来不敢用bluetoothGatt类里的connect方法,为什么呢?因为从注释里只看到了重连外设,但是不知道该怎么用,什么时候用,出了问题怎么解决。

在这里我给大家深入解析一下这个方法:这个方法是谷歌提供给大家进行重连方法,当然使用的前提就是不要执行close()方法,不能释放bluetoothGatt对象,现在大部分App工程师每次连接都会用BluetoothDevice类的connectGatt方法,收到onDisconnect回调后,执行close释放BlueotothGatt资源,不然你会发现conn_id会一直递增,递增几个之后就连接不上了,所以很多同事就会让你释放BluetoothGatt类,执行close,这里一定要等着收到onDisconnect之后再执行close方法,不然你会收不到onDisconnect回调。

讲了大家的通用做法,那么BluetoothGatt的connect能不能用吗?如果外设通常只连接一个,且不会经常改变的情况下,这个connect方法还是推荐使用的,为什么呢?因为conn_id不会递增,资源也不会释放,在前台执行时会连接比较快,且不会出错。但是呢,有时候发现执行了connect方法,很长时间都没有收到onConnect回调。那这种情况下是为什么呢?因为connect方法是一种后台的连接方法,也就是说isDirect的参数默认是false的。可能有些人不知道isDirect是什么,在大家使用conncectGatt的时候,会把autoConnect的参数设置成false,来关闭后台连接,但是大家不知道的是,你在设置这个值的时候,系统会把isDirect的值设置成true,也就说autoConnect和isDirect是一对相反的操作。你想要自动连接,那么autoConnect就会是true,相对应isDirect就是false。所以大家会用connectGatt设置autoConnect为false来提高连接效率,也就是把isDirect参数设置成了true。

所以这个也要在系统里改一下。

系统代码路径:/frameworks/base/core/java/android/bluetooth/BluetoothGatt.java

700    public boolean connect() {
701        try {
702            mService.clientConnect(mClientIf, mDevice.getAddress(),
703                                   false, mTransport); // autoConnect is inverse of "isDirect"
704            return true;
705        } catch (RemoteException e) {
706            Log.e(TAG,"",e);
707            return false;
708        }
709    }

系统路径为:/packages/apps/Bluetooth/src/com/android/bluetooth/gatt/GattService.java

379        public void clientConnect(int clientIf, String address, boolean isDirect, int transport) {
380            GattService service = getService();
381            if (service == null) return;
382            service.clientConnect(clientIf, address, isDirect, transport);
383        }

在这里,就是Framework API通过binder调用的地方,当然framework的connect传了一个false给bluetooth service。也就说isDirect为false。在这里你可以在这里强制给idDirect复制成true,就不会再出现回调很慢,甚至没有回到的情况了。

今天就更新这些,后续会继续更新,欢迎关注。

 

 

 

 

 

 

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值