美文网首页androidBLE开发
由android ble浅谈服务类SDK设计思路

由android ble浅谈服务类SDK设计思路

作者: zzzabc | 来源:发表于2016-09-15 11:50 被阅读423次

    不喜欢把一些简单的东西说成架构,在我心中架构是很大的一个东西,所以下面说SDK,就不说架构这么玄乎,就叫结构好了。

    本文分两部分,头半篇是讲android ble的结构的,对ble不感兴趣的可以直接看下半篇。

    android ble接口的结构

    android的蓝牙接口是通过系统服务提供的,这个服务是系统服务,如果root 手机会在/system/app里面会看到,类似Bluetooth.apk这样的APK。


    既然是服务,又是通过APK方式提供的,必然就是通过AIDL方式调用的了。
    所以,蓝牙里面那么多的类,虽然看起来都是业务的类,其实都只是个Wrapper,主要就是封装AIDL调用。

    BLE涉及的几个类

    BluetoothDevice

    其实看定义extends Parcelable就知道,这个所谓的Device,并不是真的device,就是个数据对象而已,内部持有了MacAddress和DeviceName(都是String)。


    BluetoothDevice.class

    可以通过connect接口+macAddress拿到BluetoothGatt对象,这是一个Ble通讯对象,下面会介绍。

    connect函数 connect函数具体实现
    BluetoothGatt

    可以用来通讯的BLE对象,跟BluetoothDevice略有不同。它是一个Wrapper,可以理解为一个句柄,不是纯数据对象,且持有了callback(所以肯定不能串行化,无法在Activity之间传递,这点很重要)。
    这个类主要干了两个事
    1.从BluetoothService申请一个ID,以后通过这个ID访问的蓝牙设备都是BluetoothDevice.connect参数MacAddress的蓝牙设备

    申请ID并绑定到指定的MacAddress

    2.注册一个远程callback,以便从BluetoothService接受BLE回调,并且转换为对外部传参BluetoothGattCallback的回调(看下图)

    注册远程回调到远程Service 远程转本地的回调

    Ble API结构特点

    系统Ble接口这么设计必然是有原因的,主要是因为系统的蓝牙服务是共享的,那么相应的BLE外设的状态(特别这点)、数据发送,对系统所有的APP是应该是共享的。

    因此,它的所有类几乎都是个Wrapper。因为BluetoothGatt是一个句柄,是无状态的,要查BluetoothGatt是否连上,只能通过注册到BluetoothGatt的callback得到的通知来存下来,或者通过BluetoothManager(一个连接到BluetoothService的Wrapper)。

    BluetoothGatt.class

    小结

    通过远程服务提供共享,中心化对象管理。通过Manager单例管理设备对象,设备对象全是无状态的Wrapper(可对同一MacAddress创建N个对象都不会冲突)。

    最不好用的地方

    BluetoothGatt不能串行化,无法在Activity间传递,当基于BluetoothGatt包装自定义的协议设备的时候,一是无法在Activity间传递,二是传递副本导致不同页面得到对象最终不是一个状态,如果不想对同一地址自定义设备创建N个,就得想办法做成静态全局的了。另外,BluetoothGatt无状态导致查询状态不直观太方便。

    硬件/服务类SDK设计思路

    主要分为单例方式和Manager方式。
    单例方式又分为纯单例模式,纯Service模式,单例Wrapper+Service方式
    Manager方式分为纯Manager方式,Manager+Service方式

    名词都是自己发明的,可能不是学名,明白意思就好了:)

    纯单例模式

    最简单的方式了,所有业务都在一个单例实现。比如我要实现一个录音APP,
    就写一个Recorder单例持有系统的AudioRecord。在App各个Activity之间可以操作。

    有人会说了,为什么要写成单例这么复杂,直接用AudioRecord不就行了。

    假如我在A的Activity启动了录音,在B Activity想操作录音相关的,由于AudioRecord不可跨页面传递(实际上即使可通过Intent传递,也是副本,不是引用),A和B页面之间的操作是无法共享状态的。

    纯单例模式优点是足够简单,缺点是无法同时存在多个业务对象,没有生命周期管理。
    这种方式在iOS平台的很多接口也有体现。

    纯Service模式

    跟单例模式一样,但是实现体是Local Service,还是上面录音APP的例子,对录音的封装就可以做成一个Service,需要用的Activity就Bind Service就可以了。
    纯Service模式优点是系统会进行生命周期管理,很android的一种思路。缺点跟纯单例一样,无法同时存在多个业务对象。

    单例Wrapper+Service方式

    这种模式的Service一般用Remote Service方式多,如果没有多APP数据共享的需求用Local Service也可以。单例Wrapper本质上就是帮用户封装了对Service的远程调用。
    比如 小米的支付SDK,集成的时候assets会放一个它的Service APK,如果用户没装过Service则会提示用户安装,如果装过了,就跟别的APP共享一个用户账号。

    小米支付SDK的文档
    从调用的示例代码来看,很明显就是单例。注意它那里的数据Bundle,这个是可以序列化的,可以用AIDL传给远程Service。 小米SDK调用代码

    纯Manager方式

    这种方式其实很少用,如果是自己的APP,可以直接用Manager+Service方式,不过有些特殊的场景不得不这样设计。
    比如 某种设备,假设叫XDevice,XDevice有状态,有缓存。当做成SDK给别人开发的时候,XDevice无法在页面传递了(传递副本也是无意义的),一般人也无法忍受很复杂的调用。

    解决办法就是定义一个XDeviceManager单例,内含一个HashMap<Handler, XDevice>。通过它用设备句柄获取到XDevice,在页面间传递的时候就传递设备句柄,对于同一个句柄永远返回同一个XDevice对象。

    其实全是静态全局的套路:(

    Manager+Service方式

    跟纯Manager方式类似,但是区别在于业务实际都是Service实现的,ManagerDevice都是Wrapper,同样的道理,如果要多App数据共享,就用远程Service,要求用户安装一个独立服务的APK。
    其实系统的BLE就是类似这样的一个接口(不完全一致)。举例子?嗯,看图。

    微软Band SDK 微软Android SDK

    获取流就是Manager=>Info=>Client,但是它们其实还是Wrapper,有兴趣可以反编译看看。。。

    总得来说Manager方式适用于有多个业务对象的情况,其余的思路跟单例方式是一样的。

    相关文章

      网友评论

        本文标题:由android ble浅谈服务类SDK设计思路

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