您的位置:首页 > 移动开发 > Android开发

Android运行时资源替换-Runtime Resource Overlay

2016-12-12 17:05 316 查看
转载来源http://blog.csdn.net/whurs/article/details/53239785


一、替换第三方应用的资源


1.需求提出

Android中当我们需要修改某个应用的一些资源时,例如app中的图片资源、文字资源和颜色等时,最直接的做法就是在应用的代码中修改对应的资源文件。以下就是一个简单的例子:



应用的目录结构



应用运行的效果

现在我们需要修改“这是原生应用的资源”这段文字,最直接的做法就是在应用中修改对应的资源内容:res/values/strings.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">RRODemo</string>
<string name="hello_world">这是原生应用的资源</string>
</resources>
1
2
3
4
5
1
2
3
4
5
[/code]

但是现在我们想要在不修改应用任何代码的情况下实现对应用中引用资源的修改。这里就可以使用Android运行时资源替换-Runtime Resource Overlay(RRO)来实现


2.RRO原理与实现

RRO是在Android5.0后引入的,能过在应用运行时加载我们指定的资源,而覆盖应用原生的资源。


2.1.RRO原理

应用运行时,通过 getString/getDrawable去调用某个资源,会将资源的resources ID 作为参数传给Framework层。同一名称但不同状态的资源他们的resources ID 是一样的,比如不同分辨率但名称相同的图片分别被放置在了drawable-hdpi/drawable-ldpi/drawable-mdpi下,但在编译时针对该图片生成的resources ID却只有一个。Framework层查找资源时会使用这个resources ID,同时结合当前系统的configuration(分辨率、语言、横竖屏),即通过resources
ID 和 configuration,系统首先会调用我们通过RRO添加的资源文件,并根据configuration使用最匹配的资源文件,如果此时没有找到文件,则再调用应用原生的资源文件。其原理如下图所示:



结合上图可以看出应用只是负责提供resource ID,系统会根据configuration中的配置(语言、分辨率等)去获取适当的资源来加载,这是两个不连续和独立的过程。RRO就发生在系统检索资源的过程中,而应用使用资源的接口不变。因此,通过RRO无需对应用做任何修改。


2.2.RRO实现

RRO的实现由overlay apk来完成,与普通的apk相比它不包含源代码,只有资源文件。一个overlay apk只能替换一个目标apk的资源,但一个目标apk的资源可以被多个overlay apk更改。使用RRO机制的前提是必须要知道待替换目标apk中的包名和资源名!下面就是一个overlay apk的例子:


2.2.1.新建overlay工程

通过Eclipse新建一个没有源代码的Android Application:



资源文件res/values/strings.xml:

<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="hello_world">这是rro加载的资源</string>
</resources>
1
2
3
4
1
2
3
4
[/code]

这里需要替换的就是hello_world的显示内容,这个名字必须和待替换的资源名(hello_world)相同,即和RRODemo项目中res/values/strings.xml中的对应的资源名字(hello_world)相同。

AndroidManifest.xml文件也需要配置:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.yulong.rrodemooverlay" >
<overlay
android:priority="1"
android:targetPackage="com.yulong.jiangyu.rrodemo" />
</manifest>
1
2
3
4
5
6
1
2
3
4
5
6
[/code]

需要额外添加一个标签,当中的targetPackage就是待替换的应用的包名(这里就是RRODemo应用的包名),priority的值是针对一个目标apk的资源可以被多个overlay apk更改而设置的一个优先级,值越大优先级越高。


2.2.2.工程精简

将这个工程拷贝出来,删除多余的文件和资源,并在根目录下添加Android.mk编译配置文件。最终精简后的工程目录如下:



只保留了AndroidManifest.xml和res/values/strings.xml这两个文件。


2.2.3.Android.mk文件

Android.mk文件编译配置文件是用来打包编译时使用的:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
#include files in src directory
LOCAL_SRC_FILES := $(call all-subdir-java-files)
#include files in res diretory
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_SDK_VERSION = current
#the name of target apk
LOCAL_PACKAGE_NAME := RRODemoOverlay
include $(BUILD_PACKAGE)
1
2
3
4
5
6
7
8
9
10
11
1
2
3
4
5
6
7
8
9
10
11
[/code]

ps:注意这里的各个配置项,不然很可能因此而编译不通过。


2.2.4.上传编译

将RRODemoOverlay工程通过xftp上传到已经编译ok的一个Android底版本的目录下,这里上传到的是:packges/apps/目录下






2.2.5.配置环境变量

退回到根目录:ws/LA.UM.5.6.r1-00500-89xx.0/运行. my-setup.sh脚本配置环境:




2.2.6.mm命令编译

进入ws/LA.UM.5.6.r1-00500-89xx.0/packges/apps/RRODemoOverlay中运行mm命令编译文件生成apk:



如果编译成功,这会提示编译生成的apk路径:



到对应的目录下将apk拷贝出来都pc上,下面就通过adb 命令将这个overlay apk 推送到手机上验证。


3.RRO验证

由于RRO是在系统层做的,Android出于安全考虑,要想RRO生效必须将生成的overlay apk放到/system/vendor/overlay目录下。

保证手机拥有root权限,通过adb连接手机与pc,进入/system/vendor/overlay,如果没有overlay目录则先使用adb remount命令,然后再新建overlay目录:



然后使用adb push命令将生成的overlay apk推送到手机的/system/vendor/overlay目录下:



ps:当需要输入apk的本地路径时,可以直接将apk拖到cmd命令窗口中,就可以自动补全完整路径了。

然后在打开我们之前的应用,验证RRO,查看应用中对应的资源是否已经改变,如果没有马上生效,可以重启手机试一试。

由此可以看出应用中的资源已经被替换了,但我们并没有修改应用的任何地方。上面的例子只是替换了string资源,实际上RRO能支持替换除了layout 和 AndroidManifest 外的所有资源,这在做ROM定制开发时非常有用。

参考博客:

http://developer.sonymobile.com/2014/04/22/sony-contributes-runtime-resource-overlay-framework-to-android-code-example/

http://blog.csdn.net/azhengye/article/details/49050631


二、替换framework的资源文件

Android的系统中有界面展示的内容一般都是以apk的形式挂载,例如设置就有一个settings.apk,如果想替换其中封装的资源,则完全可以按照一中替换第三方应用的方法来。但是,Android对于一些通用的资源,并不是直接封装在apk中的,这些通用的资源是封装在/system/framework-res.apk中的,这个apk和overlay apk类似,仅仅包含资源文件,而没有源代码。这属于系统的资源,如果想要修改framework-res.apk中的资源,可以采用反编译framework-res.apk,再修改资源文件,然后再回编译,替换原来的apk即可。而Android对于这些系统的资源,同样也给我们提供了一套RRO资源替换的机制。与上面第三方应用类似,我们首先需要找到被替换资源的apk(framework-res.apk),被替换资源的(这里改变设置里面的一个字符串storage_internal)属性名。

res\values\strings.xml

before:
<!-- Storage description for internal shared storage. [CHAR LIMIT=NONE] -->
<string name="storage_internal">Internal shared storage</string>
1
2
1
2
[/code]



after:

<!-- Storage description for internal shared storage. [CHAR LIMIT=NONE] -->
<string name="storage_internal">yulong ui storage</string>
1
2
1
2
[/code]



另外需要更改targetPackage的属性值,通过查看Android源代码文件framework\base\core\res\AndroidManifest.xml源文件可知,这里的targetPackage应为android。所以overlay apk的AndroidManifest.xml配置如下:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.jiangyu.framework.overlay"
android:versionCode="1"
android:versionName="1.0" >
<overlay
android:priority="1"
android:targetPackage="android" />
</manifest>
1
2
3
4
5
6
7
8
1
2
3
4
5
6
7
8
[/code]

配置好Android.mk文件后,在服务器的底版本环境下编译生成overlay apk

Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
#include files in src directory
#LOCAL_SRC_FILES := $(call all-subdir-java-files)
#include files in res diretory
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_SDK_VERSION = current
#the name of target apk
LOCAL_PACKAGE_NAME := framework-res-overlay
LOCAL_EXPORT_PACKAGE_RESOURCES := true
include $(BUILD_PACKAGE)
1
2
3
4
5
6
7
8
9
10
11
12
1
2
3
4
5
6
7
8
9
10
11
12
[/code]

将编译好的apk 拷贝到pc上,然后通过adb push命令将其推送到手机机vendor/overlay/目录中(如果没有overlay这个目录,新建之),和第三方应用的system/vendor/overlay/目录有所区别。最后重启手机验证是否替换成功:



ps:其实将overlay apk拷贝到vendor/overlay/和system/vendor/overlay/其中的一个目录后,在另外一个目录中也被自动拷贝了一份,原因是Android在init.rc配置文件中已经将这两个文件夹链接起来咯。

参考:

https://my.oschina.net/kingguary/blog/160190

http://www.angeeks.com/thread-3344783-1-1.html

https://github.com/ReinhardStrauch/framework-res-overlay-sample
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息