一.Android overlay
多个overlay的优先级判定
在mk文件中通过定义PRODUCT_PACKAGE_OVERLAYS或DEVICE_PACKAGE_OVERLAYS变量,后面可以加上多个overlay目录路径,以此来实现多个overlay目录。但是这些目录是有优先级顺序的,PRODUCT_PACKAGE_OVERLAYS下的目录优先级高于DEVICE_PACKAGE_OVERLAYS下目录的优先级,写在前面的目录优先级高于写在后面目录的优先级,举个例子:
1 2 | PRODUCT_PACKAGE_OVERLAYS = overlay_A overlay_B DEVICE_PACKAGE_OVERLAYS = overlay_C overlay_D |
上述overlay目录优先级顺序:overlay_A >overlay_B> overlay_C >overlay_D
PRODUCT_PACKAGE_OVERLAYS:用于一个指定的产品,即某个品牌的某个型号。
DEVICE_PACKAGE_OVERLAYS: 用于某个品牌的所有产品。
一般”device/” 路径下的overlay使用DEVICE_PACKAGE_OVERLAYS,而”vendor/”路径下的overlay使用RODUCT_PACKAGE_OVERLAYS。
overlay资源替换的前提和原则
前提:资源所在路径必须与overlay下资源路径完全相同。如要替换 Settings 这个应用的String.xml里的资源,该资源文件所在路径为packages/apps/res/values/,则对应overlay的路径必须为overlay/packages/apps/res/values/。
原则:overlay替换的是资源,不是文件。举个例子,应用中String.xml里的内容如下:
1 2 3 | <String name="a">aaa</String> <String name="b">bbb</String> <String name="c">ccc</String> |
overlay中的String.xml里的内容如下:
1 | <String name="a">abc</String> |
则最终,apk调用的资源如下:
1 2 3 | <String name="a">abc</String> <String name="b">bbb</String> <String name="c">ccc</String> |
而不是想象中的
1 | <String name="a">abc</String> |
注意,关于替换,查询相关英文文档发现有如下描述
For color, bool, string, array, style/theme types, the resource values are identifed by their keys, so for these types, there is no need to put the resources in a file with the same name as in the original base package.
For layout, animation, picture drawables and raw types, the resources are indentifed by their file name, and overlay for these resources should keep the file name same as in the base packages.
翻译成中文的大概意思就是:
1.对于color,bool,String,array,style等资源的值是有他们的键确定的,比如
1 | <String name="a">abc</String> |
该字符串资源通过键 name = “a” 来唯一确定值 abc 。也就是说,overlay里的这类资源文件的文件名不需要与应用包里的资源文件的文件名保持一致。只需要,资源文件里的键保持一致就行了。
2.对于布局文件,动画文件,图片资源文件等,这些资源文件是通过文件名来唯一确定,所以overlay里的这类资源文件需要与应用包里的资源文件的文件名保持一致。
Android 系统 overlay 机制重点小结
静态 overlay 和 动态 overlay
静态 overlay:又称为编译时 overlay,编译时资源就已经覆盖了,一般用在有源码的apk中。
动态 overlay:又称为运行时 overlay,当 apk 在手机中运行时才发生资源覆盖,一般用在无源码的apk中
静态 overlay
1.修改产品中mk文件指定overlay路径
例如:在/home/android/xxx/android/vendor/xxx/trunk/configs.mk文件中添加
1 | PRODUCT_PACKAGE_OVERLAYS += $(LOCAL_PATH)/overlay |
2.在overlay目录下创建资源文件
例如:在/home/android/xxx/android/vendor/xxx/trunk/overlay/packages/apps/Settings/res/values/config.xml
1 2 3 4 5 6 7 | <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <!-- Whether to support CT PA requirement or not --> <bool name="config_support_CT_PA">false</bool> <!-- Whether screen_pinning_settings should be shown or not. --> <bool name="config_show_screen_pinning_settings">false</bool> </resources> |
又或者/home/android/xxx/android/vendor/xxx/trunk/overlay/packages/apps/Settings/res/values/strings.xml
1 2 3 4 5 | <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="zzz_certification_settings_title">Certification</string> <string name="ringtone_title1">Phone ringtone SIM1</string> <string name="ringtone_title2">Phone ringtone SIM2</string> </resources> |
动态 overlay
RRO能直接定制替换第三方APK的资源,而不需要其源码。RRO的编译结果会得到一个xxx_overlay.apk。RRO不能替换AndroidManifest.xml文件及reference resource 类型的文件,如layout、anim、xml目录中的xml文件。虽然RRO具有自己的AndroidManifest.xml文件,但它却不能替换源项目中的AndroidManifest.xml文件。关于layout目录中的xml文件,SRO是可以替换的。
1.修改产品中mk文件指定overlay路径
因为要生成apk文件,所以要把新建目录中的Android.mk文件给包含进去
例如:在/home/android/xxx/android/vendor/xxx/trunk/configs.mk添加
1 | $(call inherit-product-if-exists, $(LOCAL_PATH)/rroOverlay/rrooverlay.mk) |
Android Makefile中inherit-product函数简介,以及与include的区别
例如:/home/android/xxx/android/vendor/xxx/trunk/rroOverlay/rrooverlay.mk
1 2 3 4 5 | LOCAL_PATH := vendor/tinno/$(TARGET_PRODUCT)/$(PROJECT_NAME)/packages/apps/ PRODUCT_PACKAGES += \ WallpaperPickerClaOverlay \ FrameworkResClaOverlay \ GmsSampleIntegrationClaOverlay |
2.在RRO的包中添加文件
例如:/home/android/xxx/android/vendor/xxx/trunk/rroOverlay/WallpaperPickerClaOverlay/AndroidManifest.xml
1 2 3 4 5 6 7 8 | <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.wallpaperpicker.overlay"> <overlay android:targetPackage="com.android.wallpaperpicker" android:priority="1" android:isStatic="true"/> </manifest> |
android:targetPackage 要与被rro应用包名一直一致
android:priority=“1” 覆盖优先级,值越大优先级越高
android:isStatic=“true” 设置该属性,才能rro,应该是O增加的
例如:/home/android/xxx/android/vendor/xxx/trunk/rroOverlay/WallpaperPickerClaOverlay/Android.mk
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | LOCAL_PATH := $(call my-dir) $(warning mike LOCAL_PATH = $(LOCAL_PATH)) include $(CLEAR_VARS) LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res#包含res资源目录 $(warning mike LOCAL_RESOURCE_DIR = $(LOCAL_RESOURCE_DIR)) LOCAL_MANIFEST_FILE := AndroidManifest.xml#指定加载AndroidManifest文件位置,可以不指定,默认是这个路径 #optional:指该模块在所有版本下都编译;user:指该模块只在user版本下才编译;eng:指该模块只在eng版本下才编译 LOCAL_MODULE_TAGS := optional LOCAL_SDK_VERSION := current #除应用(apk)以LOCAL_PACKAGE_NAME指定模块名以外,其余的模块都以LOCAL_MODULE指定模块名。 LOCAL_PACKAGE_NAME := WallpaperPickerClaOverlay#指定apk名称 LOCAL_MODULE_PATH := $(PRODUCT_OUT)/carrier_600CLA/overlay#指定编译后路径,即目标的安装路径 #自动添加overlays包里的资源 LOCAL_AAPT_FLAGS := --auto-add-overlay#用于新增资源,不覆盖原有软件包中的资源 #Android Asset Packaging Tool:aapt是Android资源打包工具,aapt2是优化过的aapt LOCAL_USE_AAPT2 := false LOCAL_AAPT_INCLUDE_ALL_RESOURCES := true include $(BUILD_PACKAGE)#建立一个APK |
然后在/home/android/xxx/android/vendor/xxx/trunk/rroOverlay/WallpaperPickerClaOverlay目录下添加要RRO的目录
通过aapt overlay
AAPT(Android Asset Packaging Tool) 在SDK的tools/目录下. 该工具可以查看, 创建, 更新ZIP格式的文档附件(zip, jar, apk).
添加文件到打包好的apk中
1 | aapt a[dd] [-v] file.{<!-- -->zip,jar,apk} file1 [file2 ...] |
解释:aapt a <你的apk文件> <要添加的文件路径>, 这个就是将文件添加到打包好的apk文件中
下面举例用代码将com.android.contacts.common和com.android.incallui一起打包到Dialer.apk
1.在Android.mk中添加如下代码
/home/android/xxx/android/packages/apps/Dialer/Android.mk
1 2 3 4 | LOCAL_AAPT_FLAGS := \ --auto-add-overlay \ --extra-packages com.android.contacts.common \ --extra-packages com.android.incallui |
–extra-packages 是为资源文件设置别名:意思是通过该应用包名+R,com.android.contacts.common.R和com.android.incallui.R都可以访问到资源
LOCAL_AAPT_FLAGS 的作用是把 –extra-packages 标签后面的包附加在要生成的APK里面
2. 将com.android.contacts.common和com.android.incallui的AndroidManifest.xml文件中的内容移植到Dialer的AndroidManifest.xml
3. 再用mm指令编译并生成Dialer.apk
到此就将com.android.contacts.common和com.android.incallui一起打包到Dialer.apk中了,因此当我们替换InCallUI.apk时不会起作用
检查overlay是否生效
用反编译的方式来检查是否生效,aapt既可以打包apk中资源文件,也可以反编译出apk中资源文件内容
1.使用AAPT检测
aapt dump 命令
1 | aapt d[ump] [—values] WHAT file.{<!-- -->apk} [asset[asset …]] |
badging-----------Print the label and icon for the app declared in APK
permissions------Print the permissions from the APK
resources---------Print the resource table from the APK
configurations----Print the configurations in the APK
xmltree-------------Print the compiled xmls in the given assets
xmlstrings---------Print the strings of the given compiled xml assetsaapt d badging xxx.apk :显示标签、图标和应用程序的相关描述 aapt d permissions xxx.apk
:显示apk所具有的系统权限 aapt d resources xxx.apk :查看apk资源 aapt d configurations
xxx.apk :查看apk配置 aapt d xmltree facebook_googleplay_V1.0.0.apk
res/anim-v21/design_bottom_sheet_slide_out.xml
:查看design_bottom_sheet_slide_out.xml的树形结构 aapt d xmlstrings
facebook_googleplay_V1.0.0.apk
res/anim-v21/design_bottom_sheet_slide_out.xml :查看xml中所有的string
2.使用apktools检测
反编译工具
二.预制apk
带源码的预制
在订单目录下内置SetupWizard
/home/android/xxx/android/vendor/xxx/trunk/configs.mk
1 | $(call inherit-product-if-exists, $(LOCAL_PATH)/packages/apps/apps.mk) |
在/home/android/xxx/android/vendor/tinno/xxx/trunk/packages/apps/目录
下新建SetupWizard目录,并把源码放在放在新建的SetupWizard目录下
/home/android/xxx/android/vendor/xxx/trunk/packages/apps/apps.mk
1 2 3 4 | LOCAL_PATH := vendor/tinno/$(TARGET_PRODUCT)/$(PROJECT_NAME)/packages/apps/ PRODUCT_PACKAGES += \ SetupWizard \ |
重写编写Android.mk文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_PACKAGE_NAME := SetupWizard LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_PRIVILEGED_MODULE := true LOCAL_MODULE_TAGS := optional LOCAL_CERTIFICATE := platform #LOCAL_OVERRIDES_PACKAGES := Provision LOCAL_PROGUARD_ENABLED := disabled LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res LOCAL_SRC_FILES := $(call all-java-files-under) LOCAL_JAVA_LIBRARIES += telephony-common LOCAL_USE_AAPT2 := true LOCAL_STATIC_ANDROID_LIBRARIES := setup-wizard-lib include frameworks/opt/setupwizard/library/common-gingerbread.mk include $(BUILD_PACKAGE) include $(call all-makefiles-under,$(LOCAL_PATH)) |
重新build项目即可
不带源码的预制
前面步骤一样
Android.mk文件
1 2 3 4 5 6 7 8 9 10 11 12 13 | LOCAL_PATH:= $(call my-dir) #system ################################################################### include $(CLEAR_VARS) LOCAL_MODULE := LegalInformation LOCAL_MODULE_CLASS := APPS LOCAL_MODULE_TAGS := optional LOCAL_BUILT_MODULE_STEM := package.apk LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX) LOCAL_CERTIFICATE := platform LOCAL_SRC_FILES := $(LOCAL_MODULE).apk include $(BUILD_PREBUILT) ################################################################### |
Android.mk文件解释
Android.mk语法规范
Android.mk解析