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

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

相关推荐
程序员小范1 天前
孙玲:从流水线工人到谷歌程序员
人工智能·程序员·谷歌·远程工作
程序员鱼皮1 天前
我发现很多程序员都不会打日志。。
计算机·程序员·开发·编程经验·java程序员
demo007x2 天前
「创意故事卡片创作助手」扣子模板使用教程
前端·后端·程序员
酷熊代理3 天前
网络安全:我们的安全防线
运维·网络·安全·web安全·网络安全·程序员
一只爱撸猫的程序猿3 天前
简单实现一个苹果支付的场景
spring boot·后端·程序员
豆包MarsCode3 天前
基于豆包MarsCode 和 Threejs 实现3D地图可视化
大数据·开发语言·人工智能·python·3d·程序员
狼叔3 天前
解读前端大牛TC39 成员Hax贺师俊:如何保持个人竞争力-浪说播客04
前端·程序员
京东云开发者4 天前
质量视角下的系统稳定性保障--稳定性保障常态化自动化实践
程序员
哔哩哔哩技术4 天前
哔哩哔哩客服坐席调度系统的演进
程序员