28、Launcher的插件化:插件化框架的选择(如RePlugin)、插件加载与资源管理、插件的生命周期
做Launcher开发做到一定阶段,你一定会遇到这个问题:怎么在不升级整个桌面的情况下,动态增加新功能?
比如,用户想要一个全新的负一屏卡片,或者一个快捷手势面板。如果每次都要发版,那体验太差了。这时候,插件化就是绕不开的路。
我最早接触插件化,是在做系统Launcher的定制项目。客户要求桌面能动态加载第三方主题和功能模块。嗯,那会儿踩了不少坑。今天我把核心经验拆开来讲。
28.1 插件化框架的选择:为什么我倾向RePlugin
市面上插件化方案不少。但用在Launcher这种系统级应用上,要求很苛刻:
- 稳定性第一——Launcher崩溃了,用户连桌面都进不去。
- 资源管理要干净——插件卸载后不能留垃圾。
- 生命周期要可控——插件不是独立App,它活在Launcher的进程里。
我个人习惯用RePlugin。为什么?
| 对比项 | RePlugin | 其他方案(如VirtualAPK) |
|---|---|---|
| 进程模型 | 插件运行在主进程,轻量 | 可独立进程,但通信成本高 |
| 资源冲突 | 内置资源隔离机制 | 需手动处理 |
| 插件热更新 | 支持,无需重启Launcher | 部分支持 |
| 系统适配 | 对Android 10+兼容较好 | 高版本有坑 |
我在项目中遇到过一个问题:某款插件化框架在Android 12上加载插件时,直接抛了ClassNotFoundException。查了半天,是系统类加载器改了行为。RePlugin在这方面做了不少兼容工作,省了我很多时间。
核心观点:Launcher的插件化,选框架的第一原则不是功能多,而是稳。RePlugin的“插件与宿主同进程”模型,天然适合桌面场景。
28.2 插件加载与资源管理:那些容易翻车的地方
插件加载,说白了就是让Launcher能识别并运行一个外部的APK文件。但这里有个关键问题:资源ID冲突。
你想想看,Launcher本身有R.drawable.ic_launcher,插件里也可能定义了一个同名资源。如果不做处理,系统会加载错。
RePlugin的做法是:重写插件的AssetManager和Resources。每个插件拥有独立的资源表,互不干扰。
代码层面,加载一个插件大致是这样:
// 加载插件APK
String pluginPath = "/data/plugin/weather_plugin.apk";
PluginInfo info = RePlugin.install(pluginPath);
// 启动插件中的Activity
RePlugin.startActivity(MainActivity.this,
RePlugin.createIntent("weather_plugin",
"com.example.weather.MainActivity"));
// 获取插件的资源
Resources pluginRes = RePlugin.getPluginContext("weather_plugin").getResources();
Drawable icon = pluginRes.getDrawable(R.drawable.plugin_icon);
嗯,这里要注意:插件里的R类不能直接引用。因为编译时插件和宿主的R是分开的。我早期犯过这个错,直接写死了资源ID,结果插件一更新就崩溃。
避坑指南:我曾经在插件资源管理上吃过亏。插件里用了getResources().getDrawable(),但没注意传入的是宿主的Context。结果图标全显示成了Launcher的默认图标。正确的做法是:始终使用插件自己的Context获取资源。
28.3 插件的生命周期:它不是一个独立App
很多人刚接触插件化时,会下意识把插件当成一个独立App来设计。这是个大坑。
插件运行在Launcher的进程里。它的Application、Activity生命周期,其实是被Launcher“托管”的。
具体来说:
- 插件Application:RePlugin会为每个插件创建一个虚拟的
Application对象,但不会调用onCreate()。所以别在插件Application里做初始化工作。 - 插件Activity:它的
onCreate()、onResume()等回调正常触发。但onDestroy()后,插件占用的内存不一定立即释放。 - 插件BroadcastReceiver:需要动态注册,不支持静态注册。
我建议的做法是:把插件设计成“无状态”的。每次启动时从Launcher获取必要数据,用完就清理。这样即使插件崩溃,也不会影响Launcher本身。
警告:不要在插件里持有Launcher的Activity引用。这会导致内存泄漏。Launcher是常驻进程,泄漏一点内存,时间长了就会卡顿。
28.4 一张图看懂Launcher插件化核心逻辑
下面这张SVG图,概括了Launcher插件化的整体流程。从框架选择到资源管理,再到生命周期控制,一目了然。
这张图把整个流程串起来了。你从框架选择开始,一步步走到生命周期管理。每一步都有对应的技术细节。我个人习惯在项目初期就把这张图画出来,这样团队沟通起来效率高很多。
个人经验:我建议你在做Launcher插件化时,先画一张类似的流程图。不用多精美,但要把资源管理和生命周期这两个最容易出问题的环节标红。这样开发时心里有数。
好了,这一章的内容就到这里。插件化是个大话题,但核心就是这三块:框架选型、资源隔离、生命周期控制。把这三点吃透,Launcher的插件化你就掌握了八成。