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

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

相关推荐
黄油饼卷咖喱鸡就味增汤拌孜然羊肉炒饭8 小时前
SpringBoot如何实现缓存预热?
java·spring boot·spring·缓存·程序员
少年姜太公12 小时前
从零开始详解js中的this(下)
前端·javascript·程序员
凌虚12 小时前
Kubernetes APF(API 优先级和公平调度)简介
后端·程序员·kubernetes
小华同学ai17 小时前
ShowDoc:Star12.3k,福利项目,个人小团队的在线文档“简单、易用、轻量化”还专门针对API文档、技术文档做了优化
前端·程序员·github
小青鱼3 天前
AI编程-Cursor从入门到精通系列之常用概念及解释(二)
人工智能·程序员
捡田螺的小男孩3 天前
参数校验的十个建议!收藏好,别再给测试机会提bug~
java·后端·程序员
哔哩哔哩技术4 天前
B站装机系统实践:从初创到规模化的演进
前端·程序员
程序员鱼皮4 天前
没事别想不开去创业!
计算机·面试·程序员·项目
绝无仅有4 天前
通用的权限管理系统的介绍与总结
面试·程序员·架构
李新_5 天前
工程师如何布置工作?
面试·程序员·团队管理