GrayMonkey
0.5 2017.10.23 11:03* 字数 2134 阅读 5810评论 0喜欢 11
前言
Android Overlay是一种资源替换机制,它能在不重新打包apk的情况下,实现资源文件的替换(res目录非assert目录),Overlay又分为静态Overlay(Static Resource Overlay)与运行时Overlay(Runtime Resource Overlay)。
源码编译流程简介
Overlay的定制需要在源码编译环境中完成,所以先简单介绍Android的源码编译流程。
首先下载系统源码,配置好编译环境,然后进入源码根目录,在Linux shell终端中执行以下步骤即可。
图1-android源码目录结构
按照google给出的编译步骤如下:
图2-envsetup.sh
图3-来自“手动编译源码”一文
参考图1中lunch命令说明,“build_varaint”可分为以下几类:
build_varaint | Description |
---|---|
eng | 工程机,具备root权限以及一些debug工具 |
user | 用户机,可正式销售给用户,无root权限、debug权限 |
userdebug | 在user的基础上开放root、debug权限 |
静态Overlay
静态Overlay,简称为SRO,发生在编译时,需要在Android系统源码环境中进行配置。
配置步骤
官方源码示例Demo如下:
1.修改产品(backup应用)的mk文件,添加如下代码
示例文件路径:
android-6.0.0_r1\device\sample\products\backup_overlay.mk
图4-官方示例
PRODUCT_PACKAGE_OVERLAYS := device/sample/overlays/backup
其中,AndroidProducts.mk定义了哪些APP会被编译打包,其他mk文件则是对应APP的配置文件。
一般厂商都会有一些个性化定制的产品,会参照device目录结构创建一个vendor目录,所以有的产品的overlay需要在这个vendor目录中进行修改。
2.在overlays目录下添加对应产品的overlay项目,overlay项目实际上就是源项目剔除代码和替换资源后的项目,注意包名路径需要与源项目保持一致。
原理
实际上,SRO的实现很简单,只是在通过AAPT打包成APK时,通过-S命令多增加了一个资源目录(overlay目录)而已,我们平时打包APK只是通过AAPT -S指定了一个资源目录,而Overlay又额外增加了一个资源目录而已。
AAPT -S命令可以指定多个资源目录,overlay的资源将替换原res中的重名文件。
图5-SRO
可见SRO在编译成APK时已经完成。
运行时Overlay
运行时Overlay,简称RRO,顾名思义,该机制的资源替换发生在运行时。
与SRO的区别
RRO能直接定制替换第三方APK的资源,而不需要其源码。SRO如上节所述,则需要对应APK的源码才能完成,一般而言,第三方是不会提供项目源码的。
RRO的编译结果会得到一个xxx_overlay.apk,加上原项目的apk,总共会有2个apk,而SRO最终只会得到一个已经完成资源替换的apk。得到的overlay.apk可以视为一个正常的apk,因为它能被安装,含有自己的AndroidManifest.xml文件,当然正常下,overlay.apk是不含有执行代码的。
RRO不能替换AndroidManifest.xml文件及reference resource 类型的文件,如layout、anim、xml目录中的xml文件。虽然RRO具有自己的AndroidManifest.xml文件,但它却不能替换源项目中的AndroidManifest.xml文件。关于layout目录中的xml文件,SRO是可以替换的。
//以下几种,就属于reference resource
Resources resources = getResources();
XmlResourceParser parser0 = resources.getXml(R.xml.test);
XmlResourceParser parser1 = resources.getLayout(R.layout.activity_main);
XmlResourceParser parser2 = resources.getAnimation(R.anim.test);
配置步骤
下面以创建Launcher3的RRO为例进行说明
创建一个新项目,包名命名为com.android.launcher3.overlay,事实上包名可以随意命名,这样命名可读性高,一看包名就知道是哪个项目的overlay。
编辑overlay项目的AndroidManifest.xml文件,文件内容如下:
其中,
android:targetPackage:需要overlay的项目的包名
android:priority:设置overlay.apk的优先级,值越大,优先级越高,用于存在多个overlay.apk情况下的判断。
替换相应的res资源
编写mk文件,编译、打包、签名,并将生成的overlay.apk输出到/vendor/overlay目录下,其中签名需要与源项目签名一致,否则不会生效。
注意:
把app放到vendor/overlay下面以后,还要activate,默认是disable的
activate有两种方式:
一种是overlay的app的清单文件中,overlay标签写 isStatic="true"
一种是加系统属性ro.boot.vendor.overlay.theme=overlay的app的包名,分号分割
PS:没有源码环境,或者不懂mk文件,可以通过root手机,直接将我们生成的overlay.apk直接push到/vendor/overlay目录下,来测试RRO机制。
部分厂商可能更改了路径,可通过adb shell pm path xxxx.overlay 查找到路径,前提是手机中已经安装了某个overlay的apk。
资源ID
我们知道资源文件在打包之后,会在R.java文件中生成一个对应的int类型资源id,这个id遵循以下的规则:
0xppttiiii
其中,
pp:01表示是系统资源,7f表示是应用资源
tt:用于表示资源类型,如string、array、图片资源等
iiii:用于表示相同类型的不同资源
原理
以我们常见的图片资源访问为例,当我们在应用层调用getDrawable方法的时候,会调用系统的getResource方法,该方法会根据资源id及设备配置信息(语言、像素密度等)来查找并返回合适的图片资源。此处,我们只关注根据id来选择资源。
如果id表明是系统资源,那么就会去framework-res.apk中查找并返回资源,一般位于/system/framework目录下,可root手机查看;如果是应用资源则在overlay和app中查找并返回。
图6-RRO流程
单个overlay包
当对应项目只有一个overlay包时,那么查找资源时,会先从overlay.apk中进行查找,查找成功直接返回,反之则从app中查找。
多个overlay包
当对应项目具有多个overlay包时,会按照overlay包的优先级从高到底依次进行查找,如果overlay包都查找失败,才会到app中进行查找。
以访问R.drawable.ic_01为例,会先从overlay1包先查找,因为其优先级最高,查找到则直接返回。
如果访问R.drawable.ic_02,先从overlay1查找,查找失败,接着从overlay2中查找,查找到直接返回。
如果访问R.drawable.ic_03,依次从overlay1,overlay2中查找,查找失败,最后会从app中查找到,并返回。
总结
SRO实际上只是利用AAPT重新打包,发生在编译时;RRO,才是overlay机制的关键,其本质是Android系统的动态资源查找机制。
实际运用当中,Overlay机制一般用于手机厂商为不同运营商做客制化定制,或者做主题换肤;一般,第三方应用是无法享受该机制的,除非与手机厂商合作,不过应用层现在也有了换肤框架Android-Skin-Loader,其本质也是利用Android的资源查找机制。