
问题引入
之前在 Android 端 App 开发中集成 Sub-Store 学习了 SubCase 这样的一个做法,后端是由 Javet驱动的这么一个方法sionnx/SubCase
正在加载仓库数据...

Extension APK 方案
那么如果要实现集成 Sub-Store 这个 feature ,那么 Javet 肯定是绕不开的, 如果做成扩展插件属性会不会可行? 答案是肯定的,Mt 管理器就是这么做的,将 二进制文件封装到扩展包中Lib
扩展 App
assets
lib
arm64-v8a
adb
bash
More Binary
META-INF
res
…
Javet 这个库排除不进行打包
build.gradle.kts
Javet 不包含的打包,那么真正需要用到的时候需要去下载扩展包 Extension Apk Demo, 在 AndroidManifest.xml 声明权限,Android 的 应用可见性(Package Visibility )机制.
build.gradle.kts
Javet 库打包到扩展 App 之后应该怎么做呢?直接时候 load 其实就可以。其实这里将库打包到扩展包中还有另一个用途, 由于之前的误判,认为 libxxx.so 需要可执行权限才可以正常 load。打包扩展包另一个用途便是从扩展包的 lib 解压保留可执行权限, 资源压缩
上面有提到对于Libxxx.so Load 不需要可执行权限,放到宿主私有目录即可, 那么从网络下载 download 也属于这一类,放到宿主私有目录然后 Load,进一步的省去了安装扩展包的复杂性
那么这样 Javet 体积问题就解决了,那么能不能对 YumeBox 进一步瘦身呢? 有的有的,还可以吧 Geo 等文件压缩一下,(ps:Geo 等文件并不包含 buildMRS.7z)CMFA 并未压缩这部分, 理论可行。那么最终选择是压缩率最高但解压慢的 xz 算法,那么最终的收益是多少呢 15MB -> 8M,收益看起来挺可观的
回到 Geo 文件本身,打包进 apk 这部分属于配置兼容性,如果不存在,内核也会自动 download,亦或者内核自动更新这部分,观察下面这部分代码,CMFA 贴的,比较安装日期然后更新 Geo 文件, 所以这部分也可以做成可选的,并不需要强制打包在 apk 内部,可通过 app 手动或者自动更新这部分,对于首次安装保持兼容性显然需要打包进去,后面如果不清除数据覆盖安装未打包的也可行
为了保持兼容性,一到两切就比较重要了,即使不需要 Geo 文件,首次安装也需要强制 builtin 版本
MainApplication.kt
Native 压缩尝试
如果Geo 文件都 xz 压缩打包了,那么能不能让 so 也压缩一下呢?上面已经证实过,宿主目录内 load 不需要可执行权限。 那么看下来,理论似乎是可行的,大体实例就是在 Java 层做一个可以, init 初始化时 load 所有的 lib
这部分在实现时遇到了阻碍,具体原因是 lib 等由 App 自己完成解压 load,安装时并未解压设置可执行权限,导致 ELF 可执行权限丢失, 一般正常 Load share 没什么问题
Native 解压 Loader
xz 是一种压缩率高,但是解压慢的算法,Java 层的 load解压速度还是太慢了,选择 Native C 语言重写,仅实现需要的部分,在实际打包时候这部分 loader并不需要 xz 压缩,需要排除 Java 层压缩
嗯,既然 lib native 都 xz 压缩了,那能不能 Java 层也 压缩下呢? 可以的 !!App
assets
lib
META-INF
res
src
classes.dex
resources.arsc
AndroidManifest.xml
…
classes.dex 文件,如果这部分也压缩的话,那么应该由谁来负责解压自己然后 load 呢, 嗯,方法就是做壳,自己解压自己然后 load 自己,那么原本的负责 load Native 的方法也放到壳里面, 这样就可以实现 Java 层也压缩的效果,而且不需要额外的依赖,复用之前的 Native 解压方法即可
那么应该怎么实现呢,详见源码 ApplicationBridge.java
loader
总结
至此,完成的从 Native Assets 到 Java 层的压缩,收益非常明显,如果在不打包 Geo 等文件,仅作为更新包安装时,体积大小仅 18-20 M ,(会随着内核大小而波动)即使打包 Geo 文件,那么依然是目前最小的 mihomo 客户端 仅仅是 Mihome 官方 Release 发布大小也差不多接近 YumeBox 更新时安装包大小,(相当于仅更新内核了说是)
