Deprecated
本文已過時,最新文章:向大家推薦《使用 AS 開發 System App》 https://xiaozhuanlan.com/system-app
0、前言:
Android原生系統帶有許多原生的App,比如瀏覽器、錄音機、計算器、設置
等,有些時候,我們需要用到一些系統的功能,或者是對已有的功能做二次開發,比如我上學時給一個公司做過一個Launcher和Wizard,就需要用到系統設置中的某些功能,比如Wifi、聲音、顯示等功能,于是就需要從Settings源碼中提取出需要的功能。
特別是公司自己定制Android系統,需要在上面做一些系統級的App
的時候,原生App已有的功能就可以通過編譯其源碼的方式直接拿過來改改就能用,而且可用度很高。
以下內容就以Settings為例,主要介紹如何編譯和運行調試Settings源碼。
1、源碼:
這里有兩種情況,分為原生
的和公司定制
的系統。無論是原生的還是定制的,類似于Settings這樣需要使用到系統級或隱藏API
的App,都需要系統簽名文件和編譯系統源碼后得到相應的jar包才可以在IDE中編譯,因為標準SDK根本沒有那些API可供調用。
舉個栗子:
鬧鐘、計算器這類的不需要額外的Jar包,得到源碼后導入IDE就可以運行的。由于包名沖突,想調試要么刪掉系統App,要么修改包名。
Settings、Launcher之類的就需要系統級的Jar包,SDK沒有提供相應API。這類的想調試就必須刪掉同包名的系統App了,修改包名會有意想不到的亂七八糟的問題出現。
(1)原生App:
網址:https://android.googlesource.com/
位置:platform/packages/apps/,可Ctrl+F搜索一下。點擊想要編譯的App,比如Settings。
使用Git克隆下來:比如 git clone https://android.googlesource.com/platform/packages/apps/Settings
需要額外的Jar就需要自己編譯系統源碼啦,這個是比較麻煩的,有興趣可以試試自己編譯定制自己的Android系統。
(2)定制:
跟公司的底層工程師要代碼。
首先是“out/target/common/obj/JAVA_LIBRARIES/”文件夾,讓底層人員整個文件夾壓縮了給到你,雖然比較大(大概1G),但這是必須的,底層人員可能會說:你要什么再跟我說,扯淡,不要聽他的,你就要全部。
再來是要Settings的源碼。
** 注意,既然是定制的,源碼、jar、簽名文件,還有系統都是一一對應的,你不能拿其他公司的系統簽名來給你公司的系統app簽名,這樣無法運行的。 **
2、編譯:
有了源碼,下一步當然是要跑起來啦。
建議都使用Eclipse來編譯,不要使用AS,因為AS編譯大型的原生App能卡到你吐血,而且出錯提示也不友好。但是用過AS的人都不想再碰Eclipse了有沒有??別急,可以先用Eclipse編譯過了,再貼到AS中,這樣好很多,也很節省時間。
步驟:
初始化:
新建工程,Compile With 選最大,Target和Min都選和你使用的系統一致,包名和原生app的包名一致,比如Settings的是com.android.settings。
新建成功后,添加libs文件夾,刪掉AndroidManifest.xml,清空res。使用Git初始化項目,添加ignore文件,提交init,方便出錯時回退。
放入源碼:
拷貝Settings源碼的AndroidManifest.xml、src、res到工程,選擇Project -> Clean清理一下,在Console會得到很多錯誤。
git commit 提交一下,還是那句話,出錯方便回退。
修正res錯誤:
首先是res下的錯誤,可能每個語言的strings.xml文件都會報錯,建議刪掉其他不需要的語言,可以根據Console的報錯信息,寫個小程序批量刪除,留下需要的,并修正錯誤即可。比如原生的代碼可能會有string重復,去掉即可。我只留下了value和value-zh-rCN的strings.xml,因為其他語言的用不到。
-
若是缺少Drawable文件,比如圖片,有以下方式可以找回來:
* Google搜索文件名,不要使用百度,百度搜不出來。
* 去SDK文件夾下全局搜索。
不要怕修改,以解決問題為優先。比如我編譯后發現缺少了@*android:drawable/XXX文件,在SDK文件夾搜索后找到該文件,放到了res/drawable文件夾后,將其引用修改為@drawable/XXX即可。畢竟只是個資源文件而已。
如果是缺少style,可以把style的名稱貼到Google中,一般都能得到正確的結果。
總之就是根據提示一直解決到res沒有提示錯誤為止。解決完畢,git commit。
修正src錯誤:
-
再來是src的錯誤,首先是必須導入的jar包,解壓底層工程師給你的JAVA_LIBRARIES文件夾,里面有很多的子文件夾。
第一個包:
文件夾:framework_intermediates
第二個包:
文件夾:core_intermediates/core-libart_intermediates(也許是其他的名字)
第三個包:
文件夾:android-common_intermediates將以上文件夾中的classes.jar,為了好區分重命名為framework-classes.jar、core-classes.jar、common-classes.jar。放到一個方便查找的文件夾中,這三個jar包將作為User Library引用。不能作為常規的jar使用。如何引用請Google。
需要注意的是:
引用后,在Java Build Path/Order and Export中,framework需排在第一、core第二、common第三。然后再Clean一下,看看src還有什么錯誤,比方說com.android.setupwizard.Test類沒有找到,就去JAVA_LIBRARIES文件夾搜索Test,再定位到其目錄下,找到其classes.jar文件,重命名后放入libs中即可。其他的錯誤也是如此。
有個比較特殊的類EventLogTags,在文件夾中根本沒有找到想要的,其使用的都是一些靜態變量。于是就直接在網上搜索靜態變量的名稱,比如EventLogTags.LOCK_SCREEN_TYPE,直接使用其值,雖然對不對,但是沒有辦法也只能先這樣了。
-
同理,也是一直解決到Clean后src沒有錯誤為止,再git commit。
建議不勾選: Window -> Preference -> Android -> Lint error Checking 的Run full error check .... 這樣有些warning和不影響運行的Lint error就不會提示,反正沒事,眼不見心不煩。
3、嘗試運行:
編譯通過了,試著直接debug跑一下,在安裝進設備的時候,就會有以下錯誤:
報錯:
Unable to execute dex: Multiple dex files define Landroid/support/annotation/AnimRes;
Conversion to Dalvik format failed: Unable to execute dex: Multiple dex files define Landroid/support/annotation/AnimRes;
這是因為Annotation曾經是作為一個單獨的庫存在的,但是由于某些原因,在最新的v4中,已經包含了Annotation了,所以,就不需要Annotation的包了,如果你沒有導入Annotation的包,就說明你導入了SDK,通過Java Build Path/Libraries,Remove掉就可以了。比如我使用的是Android N,就Remove掉AndroidN。
如果發現還有這個問題,那就是v4和v13的包沖突了,v13的包是包含v4的,把v4的包去掉就可以了。-
Installation error: INSTALL_FAILED_VERSION_DOWNGRADE:
因為系統中已經存在了Settings了,所以無法安裝。可以取得Root權限,刪掉/system/app/Settings/Settings.apk文件,刪除前記得保存一下,萬一出錯可以恢復。或者,通過右鍵選擇 Android Tools -> Rename Application Package,重命名Package,如果你的項目是GBK編碼的,重命名可能會失敗,可以通過右鍵選擇Properties -> Resource -> 選擇UTF-8即可重命名成功。此方法需慎重使用,不一定全部app都適用,如果沒有用到特殊的API就完全沒問題。因為像Settings這樣的重命名后會有很多奇奇怪怪的問題。 如果要刪除Settings.apk,提示:override rw-r--r-- root:root for 'Settings.apk'?,可以使用-rf: rm -rf Settings.apk 提示:rm: Settings.apk: Read-only file system的話,可以: mount -o rw,remount /system 重新掛載/system目錄,然后就可以刪除了,這里涉及到的跟Linux的文件權限系統有關,這里不再擴展。 其實有個軟件可以操作,如果你的設備已經Root,那么可以下載X-plore這個app,打開設置,選擇Root權限訪問,選擇超級用戶+掛載可寫,即可輕松刪除系統app,不過在刪除之前,建議備份。
Installation error: INSTALL_PARSE_FAILED_MANIFEST_MALFORMED:
AndroidMenifest.xml錯誤,據說可能是包名有大寫字母,反正我沒有。在網上查了一番,有人說是,把Activity之類的注冊寫上全名即可。但是我也沒有這樣的情況,后來找到有人說android:taskAffinity的問題,這個是啥自己搜索,我發現有些是"",有些是com.android.settings,我全更改了,可還是有這個錯誤。搞來搞去,原來是我重命名包名了,才會有這些問題,就把包名改回去了,刪掉相應系統App后,這個問題就解決了。彈出Toast有問題,我在SettingsActivity中使用Toast是有問題的,報xml解析錯誤。也不知道咋回事,沒有深入探索。
Installation error: INSTALL_FAILED_SHARED_USER_INCOMPATIBLE:
原因:apk的AndroidManifest.xml中聲明了android:sharedUserId="android.uid.system",但沒有相應的系統簽名。別急,接下來就說明如何簽名的問題。
4、調試
使用到系統級API的,或者AndroidManifest.xml文件中聲明了
android:sharedUserId="android.uid.system"
那么沒有系統簽名,直接debug簽名運行是不行的,需要向底層工程師要系統的簽名文件,在源碼目錄
build\target\product\security
下的platform.pk8
和platform.x509.pem
,如果你想看此次編譯Settings是否已成功了,可以適當的在入口加一下Log,然后導出未簽名的apk,使用系統簽名進行簽名后,放到/system/app/
下替換掉Settings.apk,然后重啟系統,打開設置,看看Logcat是否輸出里加入的Log。
系統簽名轉換成debug簽名進行調試:
在不知道系統簽名可以轉換成debug簽名前,老實說我一直都是用Log的方式調試,太特么痛苦了。現在知道后整個人都懵逼了。
我們都希望可以像調試普通app那樣調試系統app,以下是如何通過openssl
將platform.pk8
和platform.x509.pem
轉換成debug.keystore
文件:
三個命令
得到platform.priv.pem
openssl pkcs8 -in platform.pk8 -inform DER -outform PEM -out platform.priv.pem -nocrypt-
得到platform.pk12
openssl pkcs12 -export -in platform.x509.pem -inkey platform.priv.pem -out platform.pk12 -name androiddebugkey此過程提示輸入密碼,輸入android
生成debug.keystore
keytool -importkeystore -deststorepass android -destkeypass android -destkeystore debug.keystore -srckeystore platform.pk12 -srcstoretype PKCS12 -srcstorepass android -alias androiddebugkey
此方法來自:http://curlog.com/2016/08/30/android-pk2debug-keystore/
Mac自帶openssl,Linux和Win需要安裝。
然后就可以使用得到的debug簽名配置到eclipse后愉快的調試啦,當然,得先把系統中已經存在的app先刪除掉。然后重啟系統,至于如何配置eclipse的debug簽名,請Google。
5、結語:
使用過AS后,當然希望在AS中也可以調試系統App,抽空再寫篇相關編譯和調試的文章。如果這篇文章幫到你了,給個贊唄。