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处理

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

相关推荐
搜狐技术产品小编202318 分钟前
破局与重构:纯端侧 Android 自动化引擎的尝试与未来推演
android·运维·重构·自动化
码云骑士1 小时前
Android SystemServer启动过程
android·systemserver
weiggle2 小时前
第三篇:可组合函数(Composable)——Compose 的基石
android·前端
独隅3 小时前
Android Studio 接入多种不同 AI 大模型进行开发的全面详细指南(Android Studio+AI)
android·人工智能·android studio
夜微凉43 小时前
三、MySQL
android·数据库·mysql
我命由我123453 小时前
Android 开发问题:项目同时引入了两个包含相同类文件的库(AndroidX 库、旧版本支持库),导致了重复类错误
android·java·java-ee·android studio·android-studio·androidx·android runtime
anthonyzhu3 小时前
安卓Android studio panda run无法应用更新的问题
android·ide·android studio
jingling5554 小时前
Flutter | Dio网络请求实战
android·开发语言·前端·flutter
帅次5 小时前
讯飞与腾讯云:Android 实时语音识别服务对比选择
android·ios·微信小程序·小程序·android studio·android runtime
jiayong236 小时前
MySQL 排序规则冲突问题与 utf8mb4_general_ci 统一方案
android·mysql·ci/cd