Android RRO介绍与使用

Android RRO换肤

RRO全称是Runtime Resource Overlay,如名称所说它是可以在运行时动态完成换肤的一个机制。

使用方式

首先需要为target应用创建一个皮肤资源包(overlay apk),这个apk是没有任何代码的,AndroidManifest配置如下:

xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.resourceapp">

    <application android:hasCode="false" />

    <overlay
        android:targetPackage="com.example.target"
        android:resourcesMap="@xml/target_resource"
        android:category="type"
        android:priority = 1
        />

</manifest>

添加overlay标签:

  • targetPackage:表示换肤目标应用的包名
  • resourcesMap: 换肤资源Map
  • category:表示该皮肤类型
  • priority:表示overlay包的优先级,一个target应用可能存在多个overlay包,所以需要优先级来排序,值越小优先级越高

target_resource类容如下:

xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<overlay xmlns:android="http://schemas.android.com/apk/res/android">
    <item target="color/black" value="#FFFFFFFF"/>
    <item target="color/white" value="#FF000000"/>
    <item target="color/colorPrimary" value="#FFFFFFFF"/>
    <item target="color/line" value="#142B2E33"/>
    <item target="drawable/bg_theme_default" value="@drawable/bg_theme_default"/>
    <item target="string/common_sub_title" value="@string/common_sub_title" />
</overlay>

这里存放的就是皮肤资源与目标应用的map。

  • target:表示目标应用里使用到的资源名称(名称一定要和目标应用相同,这样才会建立转储关系)
  • value:皮肤资源

接着就是编译资源包-安装。

让皮肤资源包生效,两种方式:

1.可以通过adb调试。

(1)、adb shell dumpsys overlay可以查询设备中overlay包的详细信息

可以看到当前状态是false。

(2)、adb shell cmd overlay enable com.example.resourceapp使皮肤资源包生效。此时target app也会完成换肤。

2.通过OverlayManager。

java 复制代码
val overlayManager = context.getSystemService(OverlayManager::class.java)
overlayManager?.setEnabled(packageName, true, UserHandle.getUserHandleForUid(0))

需要注意的是该api只对系统应用开放。

换肤大致原理

1.资源替换

举个例子当我们给Text设置文字颜色为<color name="black">#FF000000</color>,对应R文件中的ID为0x7f060021,系统资源管理框架使用此ID查找资源时并不会立即去应用的资源包中找。

先会判断当前应用是否有overlay,如果有就会去读取当前应用和overlay应用生成的Idmap文件,这个文件记录了这两个应用之间同名资源的ID映射关系。(此文件是在overlay apk安装时由OverlayManagerService解析生成)

比如overlay应用中定义的black颜色资源ID为0x7f060010,系统会将0x7f060021替换成0x7f060010,然后拿着0x7f060010去overlay资源包找到对应的资源值,此时target应用已经完成了资源替换。

2.刷新应用

接下来就需要刷新应用页面了,OverlayManagerService会自动通知应用的activity重走生命周期达到刷新目的,不过这个重走生命周期是会保留窗口直至activity完成,所以换肤过程是无缝衔接的并不会有闪屏出现。

除了重走生命周期这种刷新方式,还可以选择修改OverlayManagerService,让它只回调应用的configurationChanged,让应用自己在configurationChanged方法中去重新set界面的资源,这样也可以完成刷新,不会使Activity重走生命周期。

实现系统整体换肤方案

所谓系统整体换肤即让系统各应用(SystemUI、Launcher、Settings等等)同时完成换肤即可。 Note:对于SystemUI这种没有Activity的应用就可以通过OverlayManagerService回调configurationChanged的方式达到刷新效果。

当overlay apk安装成功后OverlayManagerService会解析生成文件data/system/overlays.xml,这个文件存放了overlay apk包信息

xml 复制代码
</overlays>
<item packageName="com.android.theme.color.orchid" userId="0" targetPackageName="android" baseCodePath="/product/overlay/AccentColorOrchid/AccentColorOrchidOverlay.apk" state="2" isEnabled="false" isStatic="false" priority="2147483647" category="android.theme.customization.accent_color" />
<item packageName="com.android.theme.color.purple" userId="0" targetPackageName="android" baseCodePath="/product/overlay/AccentColorPurple/AccentColorPurpleOverlay.apk" state="2" isEnabled="false" isStatic="false" priority="2147483647" category="android.theme.customization.accent_color" />

......

<item packageName="com.zlingsmart.resourceapp" userId="0" targetPackageName="com.example.settings" baseCodePath="/data/app/~~w0YvN3bMjOZbRQHJ7axruw==/com.zlingsmart.resourceapp-HQ5IxRQ4Cu9WQ7tBHlS6wA==/base.apk" state="3" isEnabled="true" isStatic="false" priority="2147483647" category="day" />
</overlays>
  • packageName:overlay apk的包名
  • targetPackageName:目标应用包名
  • baseCodePath:overlay apk存储位置
  • state:overlay apk当前状态
  • isStatic:是否是静态overlay
  • priority:overlay优先级
  • category:overlay包类别

我们可以通过OverlayManager.getAllOverlays方法获取所有的overlay包信息。 Note:该方法原生OverlayManagerService中已实现,但OverlayManager没有提供该方法,需要修改OverlayManager。

接下来的工作就简单了,比如我们要实现切换黑夜主题:

  • 1.overlay应用Manifest中配置category为night,打包黑夜资源皮肤apk安装;
  • 2.OverlayManager.getAllOverlays获取所有overlay皮肤包信息;
  • 3.过滤category,OverlayManagerService enable所有对应的资源

这样就完成了整体换肤,同理可以做多套皮肤:黑夜、白天、科技、简约等等。

相关推荐
灵感__idea5 小时前
JavaScript高级程序设计(第5版):无处不在的集合
前端·javascript·程序员
dmy8 小时前
n8n内网快速部署
运维·人工智能·程序员
憨憨睡不醒啊10 小时前
如何让LLM智能体开发助力求职之路——构建属于你的智能体开发知识体系📚📚📚
面试·程序员·llm
程序员岳焱11 小时前
Java 程序员成长记(二):菜鸟入职之 MyBatis XML「陷阱」
java·后端·程序员
liangdabiao13 小时前
让AI写出真正可用的图文并茂的帖子(微信公众号,小红书,博客)
程序员
安妮的心动录13 小时前
人是习惯的结果
面试·程序员·求职
小兵张健14 小时前
笔记本清灰记录
程序员
陈随易16 小时前
Univer v0.8.0 发布,开源免费版 Google Sheets
前端·后端·程序员
陈随易2 天前
Element Plus 2.10.0 重磅发布!新增Splitter组件
前端·后端·程序员
陈随易2 天前
2025年100个产品计划之第11个(哆啦工具箱) - 像哆啦A梦口袋一样丰富的工具箱
前端·后端·程序员