Android 运行时资源替换----Runtime Resource Overlay
2015-10-12 18:46
633 查看
先抛一个问题:现在有一个第三方应用,没有代码,只有编译好的apk,在不去改动这个apk的前提下,如果想改变这个应用中的一些资源显示效果,比如改变一个button的文字,一个imageview的背景,有没有可能做到?
我的答案是有可能做到(废话,做不到的话让我怎么往下写(bian))。直接上栗子,拿蘑菇街的应用来开刀。先看下蘑菇街的部分原生效果图。
红色框中的文字就是我要改变的地方,接下来放改变后的效果图。
注意圈起来的红色部分文字已经改变了,而我并没有去改动mogujie的apk。不要问为啥替换后的文字这么的丧心病狂,我会说我被mogujie伤害过吗?
上面的这个栗子就引出了我要讲的Android 资源替换-----Runtime Resource Overlay(RRO)。RRO是在Android5.0后引入的,它能在 apk 运行时,自动加载需要定制的资源,而不加载原有的资源。mogujie的应用我压根没动,只是当系统在调用mogujie的资源的时候,我给它分配了一个同名的资源,这样系统不会去获取mogujie原生的资源,而获取的是我分配给它的资源。给出了感性的一个解释,下面开始讲解具体的原理,再次之前需要先说明下应用查找资源的过程。
应用通过 getString/getDrawable去调用某个资源时,会将这个resources ID 作为参数传给 framework 层。同一名称但不同状态的 resources ID 是一样的,比如不同分辨率但名称相同的图片分别被放置在了drawable-hdpi/drawable-ldpi/drawable-mdpi下,但在编译时针对该图片生成的resources
ID只有一个。framework 层 查 找 资 源 时会使用这个resources ID , 同时还要使 用 当前 系 统 的configuration(分辨率、语言、横竖屏)。通过 resources ID 和 configuration,系统会找到最匹配的资源(如果没有找到,则使用默认的 ),最后将找到的resources ID返回给 apk。整个过程如下图所示。
结合上图可以看出应用只是负责提供资源IDs,系统层会根据当前的语言,横竖屏,分辨率等状态去取适当的资源ID加载。这种不连续性就提供了资源欺骗的可能,RRO发生在系统层检索资源时,应用层使用资源的接口并没有改变,甚至都不知道还有一个跟它同名的资源存在,因此使用RRO更改应用的资源时无需对原来的应用做任何修改。
RRO机制的运用是依靠overlay apk实现的,与普通的apk相比它不包含代码,只有资源。一个overlay apk只能替换一个目标apk的资源,但一个目标apk的资源可以被多个overlay apk更改。在使用RRO机制的前提是必须要知道待替换目标apk中的资源名,比如我要替换mogujie在桌面的应用名称,就要知道这个应用名称是在哪个资源文件中写入的,这得依靠反编译知识,这里不详述了,直接给出
有了这个就可以开始尽情的替换了。下面就是我制作的mogujie
overlay 的目录结构。
其中AndroidManifest.xml中的内容如下:
替换的几个字串都是放在values目录下的string.xml中
这个过程的难度在于反编译后,如何正确的猜测出目标apk中资源的名称,只有拿到了正确的资源名才能保证overlay成功。到此打包编译就生成了一个overlay apk。在罗嗦下打包的apk的方法.1在源码环境下使用Android.mk文件然后进行模块化编译,这个是最方便快捷的,我刚才使用的Android.mk内容如下
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := Mogujieoverlay
LOCAL_SRC_FILES := $(call all-java-files-under,res)
LOCAL_SDK_VERSION = current
LOCAL_PACKAGE_NAME := Mogujieoverlay
include $(BUILD_PACKAGE)
2使用aapt命令打包,然后签名,必须要签名,否则打包生成的apk是无法安装的。
打包命令:
aapt p -f -I [ANDROID_SDK_PATH]/android.jar \
-S [OVERLAY_PATH]/res \
-M [OVERLAY_PATH]/AndroidManifest.xml \
-c [PRODUCT_AAPT_CONFIG] \
-F [MODULE_NAME]-overlay.apk
签名命令:
java -jar [PATH]/signapk.jar \
[PATH]/platform.x509.pem \
[PATH]/platform.pk8 \
[MODULE_NAME]-overlay.apk [MODULE_NAME]-overlay.apk_signed
由于RRO是在系统层做的,Android出于安全考虑,要想overlay生效必须将生成的overlay apk放到/system/vendor/overlay目录下才会生效。RRO的应用场景主要是在方案开发时用到,上面的例子只是替换了string资源,实际上RRO能支持除了 layout 和 AndroidManifest 外的所有资源定制,在做ROM定制开发时还是非常有用的。曾经测试报了一个google应用字串太长显示不全的问题,但google
应用压根就没有代码,只有apk,当时就是靠RRO来解决该bug的。RRO剥离了代码和资源的共生关系,在方案开发中可以针对不同的显示需求,打包不同的overlay apk,不用每次更改UI资源都去修改原来的应用。
我的答案是有可能做到(废话,做不到的话让我怎么往下写(bian))。直接上栗子,拿蘑菇街的应用来开刀。先看下蘑菇街的部分原生效果图。
红色框中的文字就是我要改变的地方,接下来放改变后的效果图。
注意圈起来的红色部分文字已经改变了,而我并没有去改动mogujie的apk。不要问为啥替换后的文字这么的丧心病狂,我会说我被mogujie伤害过吗?
上面的这个栗子就引出了我要讲的Android 资源替换-----Runtime Resource Overlay(RRO)。RRO是在Android5.0后引入的,它能在 apk 运行时,自动加载需要定制的资源,而不加载原有的资源。mogujie的应用我压根没动,只是当系统在调用mogujie的资源的时候,我给它分配了一个同名的资源,这样系统不会去获取mogujie原生的资源,而获取的是我分配给它的资源。给出了感性的一个解释,下面开始讲解具体的原理,再次之前需要先说明下应用查找资源的过程。
应用通过 getString/getDrawable去调用某个资源时,会将这个resources ID 作为参数传给 framework 层。同一名称但不同状态的 resources ID 是一样的,比如不同分辨率但名称相同的图片分别被放置在了drawable-hdpi/drawable-ldpi/drawable-mdpi下,但在编译时针对该图片生成的resources
ID只有一个。framework 层 查 找 资 源 时会使用这个resources ID , 同时还要使 用 当前 系 统 的configuration(分辨率、语言、横竖屏)。通过 resources ID 和 configuration,系统会找到最匹配的资源(如果没有找到,则使用默认的 ),最后将找到的resources ID返回给 apk。整个过程如下图所示。
结合上图可以看出应用只是负责提供资源IDs,系统层会根据当前的语言,横竖屏,分辨率等状态去取适当的资源ID加载。这种不连续性就提供了资源欺骗的可能,RRO发生在系统层检索资源时,应用层使用资源的接口并没有改变,甚至都不知道还有一个跟它同名的资源存在,因此使用RRO更改应用的资源时无需对原来的应用做任何修改。
RRO机制的运用是依靠overlay apk实现的,与普通的apk相比它不包含代码,只有资源。一个overlay apk只能替换一个目标apk的资源,但一个目标apk的资源可以被多个overlay apk更改。在使用RRO机制的前提是必须要知道待替换目标apk中的资源名,比如我要替换mogujie在桌面的应用名称,就要知道这个应用名称是在哪个资源文件中写入的,这得依靠反编译知识,这里不详述了,直接给出
有了这个就可以开始尽情的替换了。下面就是我制作的mogujie
overlay 的目录结构。
其中AndroidManifest.xml中的内容如下:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.mogujieoverylay"> <overlay android:targetPackage="com.mogujie" android:priority="1"/> </manifest>targetPackage的值必须要与mogujie应用的package值一样(反编译可以获取),priority的值是针对一个目标apk的资源可以被多个overlay apk更改"而设置的一个优先级,值越大优先级越高。
替换的几个字串都是放在values目录下的string.xml中
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="app_name">唯品会</string> <string name="host_tab_triple">不买</string> <string name="host_tab_follow">别逛</string> <string name="host_tab_msg">拒聊</string> <string name="host_tab_my">呵呵</string> </resources>
这个过程的难度在于反编译后,如何正确的猜测出目标apk中资源的名称,只有拿到了正确的资源名才能保证overlay成功。到此打包编译就生成了一个overlay apk。在罗嗦下打包的apk的方法.1在源码环境下使用Android.mk文件然后进行模块化编译,这个是最方便快捷的,我刚才使用的Android.mk内容如下
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := Mogujieoverlay
LOCAL_SRC_FILES := $(call all-java-files-under,res)
LOCAL_SDK_VERSION = current
LOCAL_PACKAGE_NAME := Mogujieoverlay
include $(BUILD_PACKAGE)
2使用aapt命令打包,然后签名,必须要签名,否则打包生成的apk是无法安装的。
打包命令:
aapt p -f -I [ANDROID_SDK_PATH]/android.jar \
-S [OVERLAY_PATH]/res \
-M [OVERLAY_PATH]/AndroidManifest.xml \
-c [PRODUCT_AAPT_CONFIG] \
-F [MODULE_NAME]-overlay.apk
签名命令:
java -jar [PATH]/signapk.jar \
[PATH]/platform.x509.pem \
[PATH]/platform.pk8 \
[MODULE_NAME]-overlay.apk [MODULE_NAME]-overlay.apk_signed
由于RRO是在系统层做的,Android出于安全考虑,要想overlay生效必须将生成的overlay apk放到/system/vendor/overlay目录下才会生效。RRO的应用场景主要是在方案开发时用到,上面的例子只是替换了string资源,实际上RRO能支持除了 layout 和 AndroidManifest 外的所有资源定制,在做ROM定制开发时还是非常有用的。曾经测试报了一个google应用字串太长显示不全的问题,但google
应用压根就没有代码,只有apk,当时就是靠RRO来解决该bug的。RRO剥离了代码和资源的共生关系,在方案开发中可以针对不同的显示需求,打包不同的overlay apk,不用每次更改UI资源都去修改原来的应用。
相关文章推荐
- android 中字节流和字符流的区别
- Android系统特有的驱动
- Android 自定义View修炼-自定义弹幕效果View
- android制,点击EditText时刻,隐藏系统软键盘,显示光标
- Android中使用Gson解析数据
- android:在android studio中使用lambda,android lambda,retrolambda
- ListView中convertView和ViewHolder的工作原理
- Android首次进入应用时加载引导界面
- Android Camera HAL3中预览preview模式下的数据流
- 关于Android工程中的主要文件夹存放的文件种类
- android客户端学习-ecplise环境变量
- Android greenDao 数据库的使用(三)
- android 使用drawable将显示状态和数据分离
- Android greenDao 数据库的使用(二)
- android应用消息处理机制
- android开机启动Service(小发现)
- android LOG机制
- mac安装android开发环境
- Android多页面传递问题(1)
- 【Android】反射