Android 蓝牙开发主要分为传统蓝牙/ble开发,前者通过建立rf通道后进行输入输出流的信息交互,后者是通过修改特征值和监听特征值来实现智能硬件和手机设备的交互。
所以开发前就要确定到底要使用哪种,因为存在着各自的优缺点。
传统蓝牙的优点:
没有限制信息的长度,能根据自我定义的byte长度进行输入,只要加上自家定义好的协议就能区分有没有错误数据,且不用担心频繁操作或者操作缺失而导致的搜索不到问题。
缺点:
搜索时间略长,与ble差距极大,调用startDiscovery后是根据接收广播逐个逐个添加的,周期为12s,也可以自己修改时间。
ble的优缺点:
1)回调方法和周期清晰,但要注意指令之间要存在时间间隔,不然会出现丢包等情况
2)搜索速度快,但快带来的坏处是30s内只能搜索5次,频繁断开重连搜索会出现状态码为6以及没数据出现的问题,具体问题出现在FrameWork层的GattService.java中的callback.onScannerRegistered(ScanCallback.SCAN_FAILED_SCANNING_TOO_FREQUENTLY, -1);
以及AppScanStats.java中的
static final int NUM_SCAN_DURATIONS_KEPT = 5;
static final long EXCESSIVE_SCANNING_PERIOD_MS = 30 * 1000;
static final int SCAN_TIMEOUT_MS = 30 * 60 * 1000;
synchronized boolean isScanningTooFrequently() {
if (mLastScans.size() < NUM_SCAN_DURATIONS_KEPT) {return false;
}return (SystemClock.elapsedRealtime() - mLastScans.get(0).timestamp)< EXCESSIVE_SCANNING_PERIOD_MS;}
啥意思呢,就是当你调用startScan或者startLeScan时,最终还是会调用下面的方法
public void startRegistration() {synchronized (this) {// Scan stopped.if (mScannerId == -1 || mScannerId == -2) return;try {mBluetoothGatt.registerScanner(this, mWorkSource);wait(REGISTRATION_CALLBACK_TIMEOUT_MILLIS);} catch (InterruptedException | RemoteException e) {Log.e(TAG, "application registeration exception", e);postCallbackError(mScanCallback, ScanCallback.SCAN_FAILED_INTERNAL_ERROR);}if (mScannerId > 0) {mLeScanClients.put(mScanCallback, this);} else {// Registration timed out or got exception, reset scannerId to -1 so no// subsequent operations can proceed.if (mScannerId == 0) mScannerId = -1;// If scanning too frequently, don't report anything to the app.if (mScannerId == -2) return;postCallbackError(mScanCallback,ScanCallback.SCAN_FAILED_APPLICATION_REGISTRATION_FAILED);}}}
而gattservice.registerScanner会调用appsanstats中的isScanningTooFrequently()方法,如果是则直接返回6的状态码,不进行下一步的搜索。
返回的回调:
@Overridepublic void onScannerRegistered(int status, int scannerId) {Log.d(TAG, "onScannerRegistered() - status=" + status +" scannerId=" + scannerId + " mScannerId=" + mScannerId);synchronized (this) {if (status == BluetoothGatt.GATT_SUCCESS) {try {if (mScannerId == -1) {// Registration succeeds after timeout, unregister client.mBluetoothGatt.unregisterClient(scannerId);} else {mScannerId = scannerId;mBluetoothGatt.startScan(mScannerId, mSettings, mFilters,mResultStorages,ActivityThread.currentOpPackageName());}} catch (RemoteException e) {Log.e(TAG, "fail to start le scan: " + e);mScannerId = -1;}} else if (status == ScanCallback.SCAN_FAILED_SCANNING_TOO_FREQUENTLY) {// applicaiton was scanning too frequentlymScannerId = -2;} else {// registration failedmScannerId = -1;}notifyAll();}}
status 6 便是频繁的回调,之后并不会触发scanFailed的方法,除了日志有相关提示外无任何提示,因此,如果想要优化,方案就有以下几种:
1.修改framework层,增加回调或者修改时间限制,就是修改我上面提到的几个文件(限定自家设备)。
2.搜索不用Ble搜索,规避频繁问题(我看了下手机的蓝牙设备搜索都是逐个递增的,因此他们的搜索方案应该就是这个)
3.ble搜索的前提下,添加搜索点击的提示(不推荐)
另外需要注意的是ble的传输限制为20个字节,通过调用requestMtu()的方式并不靠谱,分包比较实际。