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的做法是:重写插件的AssetManagerResources。每个插件拥有独立的资源表,互不干扰。

代码层面,加载一个插件大致是这样:

// 加载插件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的进程里。它的ApplicationActivity生命周期,其实是被Launcher“托管”的。

具体来说:

  • 插件Application:RePlugin会为每个插件创建一个虚拟的Application对象,但不会调用onCreate()。所以别在插件Application里做初始化工作。
  • 插件Activity:它的onCreate()onResume()等回调正常触发。但onDestroy()后,插件占用的内存不一定立即释放。
  • 插件BroadcastReceiver:需要动态注册,不支持静态注册。

我建议的做法是:把插件设计成“无状态”的。每次启动时从Launcher获取必要数据,用完就清理。这样即使插件崩溃,也不会影响Launcher本身。

警告:不要在插件里持有Launcher的Activity引用。这会导致内存泄漏。Launcher是常驻进程,泄漏一点内存,时间长了就会卡顿。

28.4 一张图看懂Launcher插件化核心逻辑

下面这张SVG图,概括了Launcher插件化的整体流程。从框架选择到资源管理,再到生命周期控制,一目了然。

Launcher插件化核心逻辑流程图 1. 框架选择(RePlugin) 2. 插件加载与安装 3. 资源隔离与管理 4. 插件生命周期管理 关键要点 • 同进程运行,轻量稳定 • 独立AssetManager • 资源ID不冲突 • 插件Application不回调 • Activity生命周期正常 • 避免持有宿主引用 • 插件设计为无状态 • 热更新无需重启 • 卸载后清理资源 章节导航 第一章 第二章 第三章 第四章 第五章 第六章 第七章 第八章

这张图把整个流程串起来了。你从框架选择开始,一步步走到生命周期管理。每一步都有对应的技术细节。我个人习惯在项目初期就把这张图画出来,这样团队沟通起来效率高很多。

个人经验:我建议你在做Launcher插件化时,先画一张类似的流程图。不用多精美,但要把资源管理生命周期这两个最容易出问题的环节标红。这样开发时心里有数。

好了,这一章的内容就到这里。插件化是个大话题,但核心就是这三块:框架选型、资源隔离、生命周期控制。把这三点吃透,Launcher的插件化你就掌握了八成。