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

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

相关推荐
我是陈泽6 小时前
一行 Python 代码能实现什么丧心病狂的功能?圣诞树源代码
开发语言·python·程序员·编程·python教程·python学习·python教学
肖哥弹架构1 天前
Spring 全家桶使用教程
java·后端·程序员
IT杨秀才4 天前
自己动手写了一个协程池
后端·程序员·go
程序员麻辣烫6 天前
像AI一样思考
程序员
一颗苹果OMG7 天前
关于进游戏公司实习的第一周
前端·程序员
万少8 天前
你会了吗 HarmonyOS Next 项目级别的注释规范
前端·程序员·harmonyos
楽码9 天前
彻底理解时间?在编程中使用原子钟
后端·算法·程序员
江南一点雨9 天前
又一家培训机构即将倒闭!打工人讨薪无果,想报名的小伙伴擦亮眼睛~
java·程序员
用户86178277365189 天前
ELK 搭建 & 日志集成
java·后端·程序员
河北小田9 天前
局部变量成员变量、引用类型、this、static
java·后端·程序员