如何工作
该部分涉及较为复杂的工作原理。一般使用者可跳转阅读快速开始。
跨进程通信
Parabox 依靠客户端与插件配合运行。单独一方运行无法发挥作用。
客户端与插件分别运行在不同进程中。不同进程间依靠 Messenger 进行通信。插件扮演服务端,主端扮演客户端,客户端可同时连接多个插件。一般情况下,客户端启动时,Parabox 依次执行以下操作:
- 使用IntentFilter筛选出符合规范的插件,将其添加至临时插件列表。
- 依次对列表中插件进行bindService操作。
- 对于连接成功的插件,客户端发送一条初始化请求。插件根据请求,结合当前运行状态启进行初始化(如启动服务)。
- 插件每次发生状态变更(启动、停止、暂停、恢复等),都会向客户端发送一条通知。客户端根据通知内容,更新插件状态显示。该状态监听将持续整个运行周期。
- 当插件返回状态为运行中时,客户端将其视作稳定连接。启用当前插件的消息发送出口。同时监听消息接收入口,接收来自插件的消息。
以上过程都已被封装成可方便调用的方法,开发者无需关心其中细节。
特别地,对于接收到的每一条 请求(REQUEST) ,都要求使用时间戳回送验证。超时未返回的请求将被视为无效,并返回超时错误。
通知(NOTIFICATION) 则不需要回送验证,但仍要求使用时间戳。
开发工具包中所有封装方法,包括消息发送/接收,状态更新,设置项更新等,都使用以上两种方式进行通信。
待接收消息缓存机制
由于连接不畅,客户端服务被杀死等特殊原因,可能会导致消息丢失。为避免这种情况,Parabox 提供了待接收消息缓存机制。
每一条消息在内部使用 请求(REQUEST) 方式进行通信。插件维护一个待接收消息缓存队列。插件从队列中取出所有消息,并尝试向客户端发送,若消息被客户端成功接收并成功存入,客户端会向插件发送一条确认回送验证,反之则发送携带错误码的回送验证。若插件收到确认回送验证,则当前传输成功,将其从队列移除;若接收到错误或触发超时错误,则将消息重新加入待接收消息缓存队列,等待下一次发送。若多次收到错误,则判断客户端断联,暂停以上循环,直至客户端重新连接并触发刷新。
若插件服务被杀死,则该缓存机制失效,消息将丢失。
以上过程都已被封装成可方便调用的方法,开发者无需关心其中细节。
FCM
由于跨进程通信方法的固有缺陷,插件与客户端需同时保持服务运行,以保证通信畅通。(插件服务用作消息接收,客户端服务用作通知推送和数据库插入)
通过 FCM ,用户可先选择将以上服务运行于其他设备(如备用机),再将消息包通过FCM传输至主力机。由于FCM消息接收由系统维护,主力机上不再需要额外运行任何后台服务,从而实现消息接收成本转嫁。
数据存储
Parabox 主要维护四类数据:会话(Contact)、消息(Message)、文件(File),连接(PluginConnection)。每类数据都具有单独的专属id,由插件提供。在实际存储中,通常还附加上插件id,以区分不同插件的数据。每种类型也具有普通类型(Model)与实体类型(Entity)。
数据类型 | 内容 | 备注 |
---|---|---|
会话(Contact) | 联系人的抽象(不区分群组与私聊),包含名称,头像等账户信息和各种配置信息 | 与连接多对多绑定 |
消息(Message) | 消息的抽象,包含消息内容,发送者账户信息 | 与连接一对一绑定 |
文件(File) | 文件的抽象,包含文件名,文件大小,文件类型,下载/备份方式等信息 | 与消息一对一绑定 |
连接(PluginConnection) | 插件与客户端的连接信息,主要包含发送消息时所需的连接数据。也用作判断会话类型 | 与会话多对多绑定 |
更多实现细节,请跳转阅读开发者文档。