一、 摘要
本文基於Android Q,介紹將AOSP中的倉庫解耦爲獨立應用時的一些疑難點。
二、 簡介
筆者在負責安卓大版本升級時,遇到很多坑,因此把這些疑難點記錄下來,一方面是爲了今後自己回顧,另一方面也是爲了幫助同行業的開發者。
考慮到數據安全,文中內容已做脫敏處理。
下面將介紹如何將AOSP中的一個倉庫解耦出來成爲一個可獨立編譯apk的應用。
三、 準備工作
首先你需要具備以下知識技能:
- 掌握Kotlin基本語法:AOSP中kt所佔比例在逐版本加大,因此,需要掌握基本的kt語法,才能順利地閱讀或修改原生代碼。
- 清楚AOSP整體架構:對於相對上層的開發者,無需重點關注內核層、驅動層的目錄結構,但需要熟悉框架層和應用層的目錄結構,以及編譯產物的目錄結構。
- 基本命令:包括repo命令、環境配置命令、整編命令、單編命令等。
- Gradle:熟悉build.gradle文件的配置。
假設你已經搞定了上述知識點,那麼接下來我們將開始一步一步解耦一個獨立編譯的應用。
四、 代碼主體解耦
待解耦的模塊,本身必須是一個git倉庫。
- 申請一個新的git倉庫,或者用已有的倉庫,創建新的分支。
- 簡單粗暴地將AOSP中這個倉庫整體拷貝過去,保持目錄結構不變。
五、 Gradle編譯環境配置
AOSP中的編譯方式不管整編還是單編,均是通過模塊根目錄下的編譯文件,舊版本上爲Android.mk
,近期已經改用Android.bp
,其類似Json格式的編寫方式,更利於開發人員閱讀和維護。
解耦爲獨立編譯應用時,就需要改爲gradle編譯的方式,因此首先需要配置build.gradle
文件,其次是本地的properties
文件,以及其他一些配置文件和腳本文件(視自身業務需求而定)。
如果執行gradle編譯命令,能開始運行並輸出結果,那麼繼續下一步。
六、 Framework資源依賴
解耦前的模塊可能使用到一些資源id,比如依賴框架層的資源id,原先由於位於AOSP環境中,因此在整編或單編時可以直接引用,但解耦出來後會因爲找不到資源id而無法通過編譯。
對此,解決方案爲通過Resources#getIdentifier獲取,示例:
原生有一處資源引用爲com.android.internal.R.string.resName
,那麼解耦後的資源id獲取方式爲:
int resId = context.getResources().getIdentifier("resName", "string", "android");
由於其最終通過AssetManager#nativeGetResourceIdentifier獲得,因此當存在大量資源id時,需要考慮對性能的影響。
七、 Proto文件動態生成類
一些模塊可能使用到源碼中沒有的java文件,其特徵會有proto關鍵詞。這便是動態生成的類。
proto文件是一種用來編譯生成java文件的文件,其配置有要生成的java文件的一些信息,包括package,className,innerClass,field等,需要藉助google的protobuf
這個庫才能編譯。
關於protobuf:
AOSP中的模塊,如果有proto文件,那麼模塊本身也是配置了對protobuf
的依賴,因此才能正常執行整編。也就是說,整編的編譯順序中,會先編譯各模塊的proto文件生成所需的java文件,再開始對AOSP整編,否則工程中有引用這些java文件就編譯不過了。
對於解耦出來的應用,不應去使用protobuf
庫自主編譯生成java文件,而是直接引用整編的編譯產物。
在Android.bp
文件中,會定義proto文件相關信息,例如:
java_library {
name: "Demo-proto",
srcs: ["src/**/*.proto"],
proto: {
type: "nano",
}
}
AOSP中proto文件的編譯產物位於:
android\out\target\common\obj\JAVA_LIBRARIES
在整編成功後的JAVA_LIBRARIES
文件夾下,就可以找到名爲Demo-proto_intermediates
的文件夾,其中便包含了我們所需的java文件。
將其中的classes.jar
重命名爲Demo-proto.jar
,複製到解耦後的工程的libs
下並配置好對其的依賴。
八、 可能遇到的問題
8.1 SDK的API缺失
通常是codebase未及時更新。
8.2 其他動態生成類缺失
查看Android.bp
文件中是否有定義相關信息, 然後再按照proto的處理方式,將缺失的類通過jar包引入。