概述
Android5.0引入了RRO,RRO全称(Runtime Resource Overlay),它可以实现在不修改三方应用源码的情况下,替换其资源,主要依靠一个叫做overlay apk的应用实现的, overlay apk和普通的应用相比最大的区别就是overlay apk不含任何代码(java或者C++),它的一般结构仅包含一个AndroidManifest.xml和res目录,当然因为需要在源码下编译,还包含一个Android.mk或者Android.bp(也可以用AS编译,前提是AS编译出来的apk需要有平台签名)。
RRO替换资源的基本原理如图:
以替换背景颜色为例:首先我们需要给View
设置背景颜色,颜色值定义在colors.xml
中,假设其值为bg_color
---->#FFFFFF,资源打包之后的ID为0x7f020001
,接着系统资源管理框架拿到这个ID并不会立即去target资源包中找,而是先判断此应用是否有overlay,如果有就会去读取target应用与overlay应用共同生成的Idmap文件,此文件中包含了这两个应用之间同名资源的ID映射关系,假设0x7f030010
就是overlay资源包中为它的bg_color
所生成的ID,此时系统资源管理框架内部就将 0x7f020001
替换为了0x7f030010
,然后拿着0x7f030010
去overlay资源包找对应的bg_color
---->#000000,至此完成资源替换。
举个栗子
直接来个栗子,我们在frameworks/base/packages/overlays/
目录下创建overlay apk,目录结构如前面的图:
AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.caic.car.rroresource">
<overlay android:targetPackage="com.example.overlaydemo" android:category="com.caic.car.theme.customization.rroresource" android:priority="1"/>
<application android:label="RROResource" android:hasCode="false"/>
</manifest>
overlay
标签表示这是一个资源overlay应用,targetPackage
表示要overlay的目标应用,priority
表示overlay包的优先级,因为一个目标应用可能存在多个overlay包,所以需要优先级来排序,值越小优先级越高。
Android.mk
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_RRO_THEME := RROResource
LOCAL_PRODUCT_MODULE := true
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_PACKAGE_NAME := RROResource
LOCAL_SDK_VERSION := current
include $(BUILD_RRO_PACKAGE)
再来看看目标应用的目录结构:
需要强调的是要想实现overlay,必须满足overlay应用的资源名称与目标应用资源名称完全相同,比如这里我们要overlay的图片ic_launcher_background.png
,目标应用运行之后就是这样:
接着编译overlay应用,编好之后将其push到设备/system/product/overlay/
中,重启之后输入命令adb shell dumpsys overlay
可以查询设备中overlay包的详细信息:
目前我这个overlay包状态是Disable的,我们输入命令adb shell cmd overlay enable com.caic.car.rroresource
,此时再dump,overlay包状态已经被enable了:
再看我们的目标应用,资源已经被换掉了:
我们就这样简单的实现了在不修改三方应用源码的情况下替换它的资源,后续文章我们再来分析RRO的相关原理与细节。