前几天抖音上看到了一张图片,一位病人躺在隔离病床上安静的看书

跟我一起学蓝牙基础篇(八)--蓝牙扫描_java

翻看一下自己年初设下的目标,有开始靠近一点吗

这一个月
有让你更了解家人吗
有让你厨艺更进步吗
有让你又多看了一本书吗
有让你习惯锻炼了吗

唉,我就是这么一针见血没有办法…

跟我一起学蓝牙基础篇(八)--蓝牙扫描_java_02

前段儿时间忙飞了,文章停更了好久.趁这段儿时间要不要一起学点儿东西

平时总在抱怨没时间写笔记,没时间看书,现在机会来了,是时候提升下了

其实蓝牙这个东西很简单,蓝牙有四大基本功能

  • 蓝牙开关 enable/disable
  • 蓝牙扫描 startDiscovery()/cancelDiscovery()
  • 蓝牙配对 createBond
  • 蓝牙连接 connect

如果不知道蓝牙该学什么,就从蓝牙的基本功能开始吧。

 

前几篇分析了蓝牙enable流程,本文来简单说一说传统蓝牙模块的扫描

这篇就是个入门,没什么难懂的代码和词语,最起码从假期到学习需要一个适应的过程~

这篇文章不是为了写多难的东西,就是为了给大家提个醒儿,一定要珍惜这次提升自己的机会

因为等你下次再想有这种大量的时间来学习,那可能就是离职找工作的时候了。

就像我那篇文章写的能够摧毁你的只有你自己,但同样,能够成就你的也只有你自己~

   break  

蓝牙扫描的作用是什么?扫描附近可发现的蓝牙设备

很简单一个定义,是不是觉得没什么可说的。但中文的博大精深,每个词都包含了太多套路

注意,三个关键词,附近、可发现、蓝牙设备

也就是说,首先扫描到的是开启蓝牙的设备

其次是附近也就是蓝牙有一定的距离限制,理想条件是10m-100m,具体要看是否有遮挡,蓝牙天线的发射功率等等

最后,可发现。对端蓝牙设备仅仅开启蓝牙还不够,还要能够被发现。怎么能够被发现?对端蓝牙设备要开启可检测性,也就是对周边蓝牙设备可见

所以,蓝牙扫描的前置条件是

  • 本机蓝牙开启扫描
  • 对端蓝牙设备开启蓝牙
  • 对端蓝牙设备在蓝牙通信的范围内
  • 对端蓝牙设备开启可检测性

ok,以上就属于一些物理条件了,接下来看看代码层面也就是逻辑层面有哪些要求

   break  

那就从蓝牙扫描的API入手BluetoothAdapter#startDiscovery()。

这是你应用可以直接调用的sdk方法。

这个方法干了什么呢

 public boolean startDiscovery() {
        if (getState() != STATE_ON) {
            return false;
        }
        try {
            mServiceLock.readLock().lock();
            if (mService != null) {
                return mService.startDiscovery(getOpPackageName(), getFeatureId());
            }
        } catch (RemoteException e) {
            Log.e(TAG, "", e);
        } finally {
            mServiceLock.readLock().unlock();
        }
        return false;
    }
代码也很简单第一,判断蓝牙是否是开启状态,如果非STATE_ON,那么不开启扫描第二,就是调用蓝牙的服务AdapterService去执行扫描方法了,在调用时需要加锁扫描包含两个阶段第一个阶段是12秒的Inquiry Scan扫描,第二个阶段就是去请求扫描到的每一个蓝牙设备的BluetoothName,也就是PageScan扫描这个方法是异步调用,调用之后会立刻返回一个boolean值,来表示方法调用成功至于何时开启扫描何时结束扫描,则需要通过注册广播来监听1,监听蓝牙扫描的开启BluetoothAdapter#ACTION_DISCOVERY_STARTED2,监听蓝牙扫描的结束BluetoothAdapter#ACTION_DISCOVERY_FINISHED3,监听扫描到蓝牙设备BluetoothDevice#ACTION_FOUND   break  蓝牙扫描是一个重量级的过程,比较耗带宽如果在已连接的状态下进行蓝牙扫描,那么该链路的带宽会被限制,通信的延时也是增加。毫无疑问,肯定会影响现有连接所以这也是为什么很过开发人员在请求蓝牙连接时会先去调用cancelDiscovery停止扫描。即便是别的应用开启的扫描,你的应用也可以调用api来让系统应用停止扫描   break  

接下来继续看蓝牙服务中的扫描方法具体实现AdapterService#startDiscovery()

其他进程可以直接调用系统的API,但如果想要调用蓝牙的服务,那就属于跨进程IPC调用了所以流程就是系统持有蓝牙服务的代理,通过代理调用public的方法,之后代理再去调用真正的蓝牙服务的方法首先是,蓝牙服务的代理中方法的实现
 @Override
        public boolean startDiscovery(String callingPackage, String callingFeatureId) {
            AdapterService service = getService();
            if (service == null || !callerIsSystemOrActiveUser(TAG, "startDiscovery")) {
                return false;
            }

            enforceBluetoothAdminPermission(service);

            return service.startDiscovery(callingPackage, callingFeatureId);
        }
首先,callerIsSystemOrActiveUser判断调用者是不是前台进程或者是系统进程接下来需要看应用是否有Manifest.permission.BLUETOOTH_ADMIN权限最后就是去调用蓝牙服务的扫描方法,代码就不贴了,想要获取扫描列表的话还需要一个位置权限,之后就是jni调用了所以要实现蓝牙扫描的功能必须要请求相应的权限
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
其中位置权限是dangerous的权限,需要动态申请ok,下一篇就该jni往后了And最后,不一定非要学蓝牙,建议自己看看面试题什么的,来分析下自己的短板,趁这个假期一定要好好补一下

跟我一起学蓝牙基础篇(八)--蓝牙扫描_java_03

原创声明

本文为作者原创文章,未经本人同意,禁止转载和挪作他用

https://mp.weixin.qq.com/s/puBkCJtckdlmxjBTheWa2A