[Android] Runtime Resource Overlay 遇到的大小事
起源:
我們的APP裡面有些部分是google GMS的頁面,基本上這些頁面是沒辦法做客製的只能從他給定的幾個的theme中選一個套用,而套用的方式為:塞一個name為theme_type的String到values/strings.xml中,字串內容則為他給定的theme名稱。
之所以會去研究這件事情,是因為被指派了一個需求:我們的APP需要在某些狀況下換theme,自己的部分換theme很簡單,但GMS部分的theme卻是寫在resource中,所以在runtime中換置換那個叫做"theme_type"的字串內容就變成主要需求。
試過這個方法:https://stackoverflow.com/a/42936357/4473021
但基本上是沒效的,後來才發現有RRO這個機制
RRO是什麼:
是一個Android 5.0後出現的機制,允許你可以在不用修改某隻app(A app)code的狀況下,以安裝另一隻overlay apk(B app)的方式,影響framework回傳resource ID的導向機制,即是:A app本來應該要取用某些resource內容時,會被自動導向去取用B app中的內容。
大致上是怎樣:
就是寫一隻overlay APP,裡面不需要有src/部分,只需要有res/的部分,並在res裡面用與原APP中相同的name去定義resource(strings, colors…etc),接著把這隻apk push進機台裡面。
用個例子開始吧:
1. overlay target app
首先先製作一個等一下需要被覆蓋的APP,簡單寫一個只有一個button的activity的APP:
最後app大概會長這樣:
2.overlay app
寫另一隻APP,企圖改掉button的內容,app的background color
可以注意到的是:
- AndroidManifest.xml中 overlay tag裡, android:targetPackage要填上覆蓋目標app的packagename;android:priority代表若存在多個overlay時的優先權(對,可以對同一個app做多個覆蓋,我覆蓋你的覆蓋)
- colors.xml和strings.xml中的name,則需要和目標app中的name一致才能完成覆蓋。你可能會想:如果我要覆蓋非系統原生的資源(system UI)或是像前言所提是自己的app,不知道resource name怎辦?這時候就是反組譯出場的時候喽
- 這支APP裡面沒有src/
結構如下:
3.build overlay apk
做這點小事就沒用Android Studio了,我是用aapt打包apk並用signapk.jar去做signkey的動作,貼一下我的指令:
> 打包$ aapt package -f -M AndroidManifest.xml -S res/ -I ~/Android/Sdk/platforms/android-28/android.jar -F myOverlays.apk
> sign key$java -jar signapk.jar platform.x509.pem platform.pk8 myOverlays.apk myOverlays_signed.apk
聰明的同學可以忽略不要看。
4.安裝overlay app
說是安裝,但需要用push的,push到機台中的/system/vendor/overlay/
首先
$ adb root
$ adb remount//創建overlay的資料夾
$ adb shell
$ adb mkdir -p /system/vendor/overlay
$ exit
有些機台可能本來就有overlay的dir了,像敝司的機台有蠻多客製化的東西,所以overlay的資料夾就已經存在了
接著把apk push進overlay中
$ adb push myOverlays_signed.apk /system/vendor/overlay
push完就重開機吧。
5.啟用overlay
push進去不一定會直接有效,可以下以下指令:
$ adb shell cmd overlay list
會顯示機台中所有overlay的項目,目標以及overlay app的對應列表,以及啟用狀態,像這樣:
可以看到目標(timothy.test.com.myapplication)底下有剛剛我們app的package name(com.test.application.overlay),前面有個[X],表示這個overlay是已經啟用了
如果沒有打叉,那就執行以下command啟用:
$ adb shell cmd overlay enable — user 0 com.test.application.overlay
執行完之後再重開機一次。
6.結果
打開overlay target app,就可以發現該覆蓋的地方已經被覆蓋掉了(背景顏色 & button的字樣)
7.結語
當然啦,如果你只是要完成例子中的目的,有更簡單的方式,不需要額外寫一隻app來做overlay。工作上用到的問題,順手memo一下,在系統廠工作總是有一些莫名其妙的需求。