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,抽空再写篇相关编译和调试的文章。如果这篇文章帮到你了,给个赞呗。