SystemUI Plugin 简介及使用

一、技术背景

SystemUI结构复杂,模块数量众多,最重要的是SystemUI属于常驻进程是一个系统的门面,且不能自升级,如果定制功能对主项目做复杂的修改,首先会造成适配压力,如果对主框架不甚理解,有可能会造成很多隐藏的Bug,且不易修复,一旦崩溃对整个系统的影响很大,那么怎么才能在不修改主结构的基础上定制我们自己的功能呢?

Google的SystemUI团队对该模块做了插件化的功能,可以动态实现对SystemUI的修改,一方面在一定程度上解决了不能自升级造成的问题,另一方面也解决了定制功能和原生主框架的解耦,再者,即便使用Plugin实现的功能crash了,也不影响SystemUI的运行,保证了稳定性。

所以SystemUI Plugin机制在运行稳定性、代码健壮性、项目兼容性等方面都是很好的选择!

二、代码组成

SystemUI的Plugin项目开发主要涉及四部分代码模块:plugin、plugin_core、share的plugins模块和systemui内部,下面分别介绍各个模块的作用。

2.1 plugin

以interface的形式定义了SystemUI支持的插件,包括NavigationEdgeBackPlugin、VolumeDialog、GlobalActions等,其中子模块ExamplePlugin是Google提供的示例,子模块VolumeDialogPlugin是我本地移植原生Volume后的模块,结构如下


ExamplePlugin和VolumeDialogPlugin都是一个完整的项目,VolumeDialogPlugin我是根据Google提供的ExamplePlugin的位置,在同目录下新建了VolumeDialogPlugin并实现,这两个项目都是可以通过单编编译成APK进行push的,这个后面会讲到,有兴趣的同学可以尝试将自己要实现的项目新建到plugin同一级别的目录尝试一下,应该也是可以的。

2.2 plugin_core

    该模块主要定义plugin使用的注解类


plugin/plugin_core这两个目录对SystemUI的可被插件替换的业务进行interface声明。这里的东西是SystemUI和plugin apk共同引用,最好不要修改,修改会导致插件不识别甚至crash。

2.3 share/com.android.systemui.shared.plugins

    该模块是插件化的核心模块,从插件的读取、加载到禁用等逻辑都是在这里实现


2.4 systemui

这里systemui就是plugin插件的调用方,下面实现举例可以加深我们对第三部分的理解。

三、实现举例

我们通过分析systemui模块自带的ExamplePlugin工程,看看plugin机制是怎么一步步的完成并在systemUI中运行起来的,需要注意的是为了保证安全,非debug的版本,只有config_pluginWhitelist列表里的插件会被读取。

3.1 ExamplePlugin的实现

3.1.1 在plugin项目中定义接口OverlayPlugin

OverlayPlugin必须继承Plugin接口,并且必须定义ACTION和VERSION字段,在类头部使用注解


ProvidesInterface对ACTION和VERSION进行声明,详细见上图

3.1.2 在ExamplePlugin的AndroidManifest对OverlayPlugin进行注册


使用service进行注册,但它并非是真正的service,所以android:exported的值必须设置为false

同时action必须和OverlayPlugin类中定义的ACTION保持一致,另外必须加上权限

<uses-permission android:name="com.android.systemui.permission.PLUGIN" />

3.1.3 实现OverlayPlugin


注意实现类需要Requires注解进行声明,包括target和version。

3.1.4 在SystemUI的文件StatusBar.java进行调用


主要看onPluginConnected和onPluginDisconnected,OverlayPlugin主要实现对NotificationShadeWindowView的替换

3.1.5 实机操作

根据ExamplePlugin的Android.bp中项目的name,在终端进行单编,完成后会在out\target\product\k6877v1_64\system\app目录下生成MtkExamplePlugin包(基于CP05),将该包中的APK push到手机/system/app/下重启,就可以看到systemui中NotificationShadeWindowView对应的xml文件被修改了颜色

3.2 VolumeDialogPlugin的实现

VolumeDialogPlugin完成编译并push到手机上,这时候SystemUI有两套Volume的模块,从

VolumeDialogComponent.java的构造函数中可以看到,首先允许插件引用systemui中实现的VolumeDialogController,然后加载VolumeDialogPlugin,如果不成功,则使用default中的实现,代码如下

// 允许插件引用systemui中实现的VolumeDialogController

Dependency.get(PluginDependencyProvider.class)

        .allowPluginDependency(VolumeDialogController.class);

//加载插件

Dependency.get(ExtensionController.class).newExtension(VolumeDialog.class)

        .withPlugin(VolumeDialog.class) //在plugin模块中定义的接口

        .withDefault(this::createDefault) //设置默认的实现

        .withCallback(dialog -> {

        //初始化完成后,回调,这时候通过打印mDialog的路径就可以知道

        //我们现在使用的具体是哪一个Volume模块

            if (mDialog != null) {

                mDialog.destroy();

            }

            mDialog = dialog;

            mDialog.init(LayoutParams.TYPE_VOLUME_OVERLAY, mVolumeDialogCallback);

        }).build();

实现前


实现后:


VolumeDialogPlugin模块是我自己把原生的Volume模块从SystemUI中移植到Plugin中的实现,细节不在赘述,但是有没有注意到3.1.4中在statusbar.java中调用方式和3.2最开始介绍的调用方式有所不同?

两种不同的调用方式,我认为是针对不同的场景,第一种通过PluginManager调用的方式,主要是用在对SystemUI已经有的文件进行覆盖式的修改,有点类似overlay机制;第二种通过Dependency.get的方式主要是针对某一个完整的模块,直接替换,或者我们需求新增的模块,通过在SystemUI中加入少量的类似上面的代码,直接使用。我们可以根据不同的需求场景进行选择,有兴趣的同学可以更深入的研究探讨一下。

四、代码分析

后续补上

参考

https://android.googlesource.com/platform/frameworks/base/+/master/packages/SystemUI/docs/plugins.md

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350

推荐阅读更多精彩内容