Skip to content

Kime2.0 艰难的的插件化

kingzcheung
Published date:
Edit this post

我最早在 Tachiyomi/Mihon 上看到插件化的实现。Mihon 是一个漫画阅读容器,而它的漫画源是以插件的形式提供内容的。后来使用 fcitx-android 的时候,又一次看到了插件化的功能实现。

虽然我不是 android 开发者,但是一直对这个设计充满好奇。于是在实现 Kime 的时候,想到联想词的模型、语音转文本功能、表情包功能应该是多样化的。比如,联想词在我这里需要在数据集上加入我自己的聊天记录,语音转文本功能可能需要不同的 ASR 模型,表情包也可能每个人使用的都不一样。

这正好可以被我用来试验插件化的功能。

研究

我对fcitx-android 和mihon的插件系统都做了一些研究。 事实上,我是优先选择fcitx-android做为借鉴对象,因为同为输入法,想来应该很简单吧?

并没有。

这里说大概说一下android 插件的实现思路,简单来说,就是 classloader。通过classloader 加载插件代码,如果有资源包,则宿主assets 管理去把资源包复制过来。 这是一种同进程交互的常规做法。与其说是插件,不如说是假装成apk的资源包,因为它没有自己的生命周期。

还有一种更复杂的事跨进程通信的,插件有自己的生命周期,但是是否可行我没试过。

由于权限问题,2个apk的通信有非常非常多的限制,所以 classloader 能干的事非常的少。

插件化思路

Mihon

Mihon(继承自 Tachiyomi)采用代码加载型插件架构,扩展本质上是独立编译的 APK,通过 DexClassLoader 在运行时动态加载代码类。

Fcitx5 Android

Fcitx5 Android 插件系统相对比较复杂,它有2类插件:数据插件、服务插件。

数据(native 库文件)插件: 纯数据提供者,像:rime、anthy、hangul、chewing 等输入法引擎插件仅在启动时将数据合并到主应用数据目录。

服务插件:通过 IPC 与主应用实时交互,比如clipboard-filter。

插件对比

Fcitx5 AndroidMihon
1. PackageManager 查询1. PackageManager 查询
2. 解析 plugin.xml2. 检查 Feature 声明
3. API 版本验证3. 签名哈希提取
4. 解析 DataDescriptor4. 信任列表验证
5. 合入 DataHierarchy5. 版本范围检查
6. 计算 Diff6. 创建 ClassLoader
7. 执行文件操作7. 反射加载源类
8. (可选) 绑定 IPC Service8. 实例化 Source
失败类型:失败类型:
---------------------------------------------------------------
- 路径冲突- Untrusted (签名未信任)
- 元数据解析错误- Error (加载失败)
- API 不兼容

通过对比,发现 Mihon 方案更适合我。

实验

kime 1的时候,我有三大功能想插件化:

  1. 表情,斗图
  2. 联想词
  3. 语音转文本

联想词想插件化的原因很简单,因为我需要训练属于我自己联想词模型,由于训练数据会带上我的私人数据,这肯定不适合开源出来。而可能别人也有类似的需要呢?插件化不错的选择。

语音转文本说到底就是ASR模型,无论是线上api接口还是纯本地的小模型,也很适合做成插件。

困难

kime 1的时候,在实现表情和联想词的时候就已经碰到了很多困难,再实现语音转文本时,已经变得不可持续。

比如 Pro Guard 规则和R8混淆,如果不开启R8混淆,安装包会非常的大,而如果开启R8混淆,插件和主app之间会因为名称混淆造成找不到类的问题。还有一些插件权限,依赖路径冲突都需要严格对齐。这些问题让开发插件简单化变成不可能的事。如果这些问题无法和主app 解耦,那插件化没有一点意义。

但是也明白一个事情,想要简单化,插件本身就不能引用其他依赖,只能依赖主app的依赖。

放弃

经过一番挣扎, 最终 ,kime 2只保留了斗图表情插件,联想词和语音转文本都内置进了主app。

除了上面的原因,还有一个原因是,联想词和语音转文本的实现是比较复杂的,它不仅需要开发插件的人会android ,还得会模型推理。如果联想词和语音转文本都引入了onnxruntime,而版本还不一样,主app又如何应对? Pro Guard又如何应对? 而且多个同类型的插件又如何处理?

相反,表情插件归根到底只是个资源包,假装成apk只是为了方便安装和卸载,同时也不会有什么复杂的逻辑,就很适合插件化。

Previous
The Difficult Plugin System of Kime 2.0
Next
I Trained a Predictive Text Model for My Own Mobile Input Method