SystemUI插件开发指南

在 Android 系统中,SystemUI 是负责状态栏、通知栏、快捷开关、锁屏等核心系统 UI 的关键组件。传统上,这部分能力完全由系统内置代码实现,扩展和定制成本较高。

为了解耦系统 UI 与定制逻辑,Android 提供了 Plugin(插件)机制,允许在不修改 SystemUI 主体代码的情况下,对系统 UI 行为进行动态扩展。这也是车机、定制 ROM、厂商 UI 中非常重要的一种扩展手段。

一、什么是 SystemUI 插件?

简单说,SystemUI 插件就是:

一个运行在独立 Context / ClassLoader 中,但被 SystemUI 动态加载并调用的扩展模块

它具备几个关键特征:

动态加载:通过反射 + ClassLoader 加载 APK

接口驱动:通过接口(Plugin Interface)与 SystemUI 通信

资源隔离:插件拥有独立的资源体系(pluginContext)

生命周期托管:由 SystemUI 控制创建、销毁

你可以把它类比为:

👉 类似 Android 的"系统级热插拔组件"

二、为什么需要插件机制?

从工程角度看,插件机制解决的是三个核心问题:

1️⃣ 解耦(Decoupling)

SystemUI 主体代码不需要知道具体实现细节,只依赖接口:

java 复制代码
@ProvidesInterface(action = OverlayPlugin.ACTION, version = OverlayPlugin.VERSION)
public interface OverlayPlugin extends Plugin {

    String ACTION = "com.android.systemui.action.PLUGIN_OVERLAY";
    int VERSION = 4;

    /**
     * Setup overlay plugin
     */
    void setup(View statusBar, View navBar);
}

插件实现在插件apk中:

java 复制代码
class MyOverlayPlugin : OverlayPlugin {
    override fun setup(View statusBar, View navBar) {
        // 自定义逻辑
    }
}
<service
    android:name=".MyOverlayPlugin"
    android:exported="false"
    adroid:label="@string/plugin_label"
    tools:ignore="Instantiatable">
    <intent-filter>
        <action android:name="com.android.systemui.action.PLUGIN_OVERLAY" />
    </intent-filter>
</service>

2️⃣ 动态扩展(Extensibility)

无需修改系统源码即可扩展功能,例如:

自定义状态栏 UI

替换 QS(Quick Settings)面板

插入悬浮层(Overlay)

修改锁屏行为

3️⃣ 调试与实验(Experimentation)

插件机制天然适合:

A/B 实验

功能灰度发布

快速验证 UI/交互方案

SystemUI 如何加载插件

PluginListener PluginInstance PackageManager PluginActionManager PluginActionManager.Factory PluginManagerImpl SystemUI PluginListener PluginInstance PackageManager PluginActionManager PluginActionManager.Factory PluginManagerImpl SystemUI 存储action到mPluginPrefs loop [遍历每个插件服务] 监听包安装/更新/卸载事件 addPluginListener(action, listener, cls, allowMultiple) create(action, listener, cls, allowMultiple, isDebuggable) 返回 PluginActionManager<T> 实例 loadAll() 在后台线程执行 queryAll() 检查并断开现有插件实例 清空 mPluginInstances 列表 queryIntentServices(intent) 查询插件 返回 ResolveInfo 列表 验证插件权限和有效性 create(context, appInfo, component, pluginClass, listener) 返回 PluginInstance 添加到 mPluginInstances 列表 在前台线程执行 onPluginConnected() onCreate() onPluginConnected(plugin) 同步块 - 将listener和actionManager存入mPluginMap startListening() 注册包变更广播接收器

资源及异常隔离

  1. systemuiapk 通过独立的classloader来加载,
    实现与systemui的资源隔离,
java 复制代码
        private ClassLoader getParentClassLoader(ClassLoader baseClassLoader) {
            return new PluginManagerImpl.ClassLoaderFilter(
                    baseClassLoader,
                    "androidx.constraintlayout.widget",
                    "com.android.systemui.common",
                    "com.android.systemui.log",
                    "com.android.systemui.plugin");
        }

只有这几个包资源共享,其他类插件跟systemui都是隔离的

java 复制代码
  private class PluginExceptionHandler implements UncaughtExceptionHandler {

        private PluginExceptionHandler() {}

        @Override
        public void uncaughtException(Thread thread, Throwable throwable) {
            if (SystemProperties.getBoolean("plugin.debugging", false)) {
                return;
            }
            // Search for and disable plugins that may have been involved in this crash.
            boolean disabledAny = checkStack(throwable);
            if (!disabledAny) {
                // We couldn't find any plugins involved in this crash, just to be safe
                // disable all the plugins, so we can be sure that SysUI is running as
                // best as possible.
                synchronized (this) {
                    for (PluginActionManager<?> manager : mPluginMap.values()) {
                        disabledAny |= manager.disableAll();
                    }
                }
            }
            if (disabledAny) {
                throwable = new CrashWhilePluginActiveException(throwable);
            }
        }

插件崩溃后:

立即禁用: 通过 PluginEnabler.setDisabled() 标记为禁用状态

触发重启: 包装成CrashWhilePluginActiveException异常抛给uncaughtException处理

持久化: 禁用状态会保存,下次启动也不会加载

相关推荐
芋只因3 小时前
MySQL 分库分表与 MyCat 的使用
android
Ehtan_Zheng3 小时前
Jetpack Compose 与 RecyclerView 混合布局的性能债
android
Kapaseker4 小时前
MVVM 旧城改造,边界划分各有招
android·kotlin
我滴老baby4 小时前
多智能体协作系统设计当AI学会团队合作效率翻十倍
android·开发语言·人工智能
StockTV4 小时前
新加坡股票API 实时行情、K 线及指数数据
android·java·spring boot·后端·区块链
草莓熊Lotso5 小时前
LangChain从入门到精通:环境搭建→核心能力→LCEL链式编程全实战
android·java·linux·服务器·langchain
私人珍藏库17 小时前
【Android】聆听岛[特殊字符]聚合全网音乐[特殊字符]免费听歌下载神器[特殊字符] 聚合音乐平台|无损母带下载|歌词封面同步|免费无广告听歌工具
android·人工智能·工具·软件·多功能
YF021118 小时前
Android触摸机制与自定义 View 实战
android·app
Dabei19 小时前
Android TV 焦点处理详解:遥控器与空鼠
android·前端