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所有对应的资源

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

相关推荐
SimonKing11 小时前
分享一款可以管理本地端口的IDEA插件:Port Manager
java·后端·程序员
SoleMotive.1 天前
一个准程序员的健身日志:用算法调试我的增肌计划
python·程序员·健身·职业转型
万岳科技程序员小金1 天前
多商户商城系统源码 + APP/小程序开发:技术架构与应用解
程序员·开源·源码·多商户商城系统源码·多商户商城小程序·多商户商城app开发·多商户商城平台开发
NAGNIP1 天前
程序员效率翻倍的快捷键大全!
前端·后端·程序员
阿里嘎多学长2 天前
2026-02-03 GitHub 热点项目精选
开发语言·程序员·github·代码托管
修己xj2 天前
山野的风,城市的窗:一位拾粪爷爷与我的时代之问
程序员
沈二到不行2 天前
【22-26】蜉蝣一日、入樊笼尔
程序员·ai编程·全栈
AI绘画哇哒哒2 天前
【干货收藏】深度解析AI Agent框架:设计原理+主流选型+项目实操,一站式学习指南
人工智能·学习·ai·程序员·大模型·产品经理·转行
程序员鱼皮3 天前
刚刚,Claude Opus 4.6 和 GPT-5.3-Codex 同时炸场!AI 编程要变天了
计算机·ai·程序员·互联网·软件开发
Stephen_Young4 天前
32岁程序员猝死:让我想起了我曾经的加班经历,庆幸自己还活着
程序员·工控