添加有源码apk到系统目录下编译(使应用拥有系统应用权限)

转载请注明出处:http://blog.csdn.net/aaa111/article/details/55265984

需求

当我们的应用想要使用一些系统应用才能使用的功能时该怎么办呢?如何让我们的应用“ 变成 ”系统应用?
现在我写了一个测试demo,用于打开GSP,但是2.3(还是2.1?)以后不允许三方应用直接打开location开关。 那我们该怎么做呢?
先不管应用系统(system app)的限制,我们照常写app。权限该添加的添加,即使出现下面的提示:

然后安装运行,应用可能强退或者操作无响应。
大概log会提示
    
    
    
    
  1. Caused by: java.lang.SecurityException: Permission denial: writing to settings requires:android.permission.WRITE_SECURE_SETTINGS
没关系,下面我们有三种方法让这个应用可用。
1. 给应用系统签名
2. 不带源码直接放apk,mm编译
3. 带源码mm编译
生成的apk放到system/app 或者priv-app目录下,让系统认为这是一个系统应用。
第1个方法最快, 第2,3可以应用到预置apk的需求中。
下面我们分别说一下具体的步骤

1. 给应用系统签名

说起来简单也不简单。说简单因为就一条命令:
    
    
    
    
  1. java -jar signapk.jar platform.x509.pem platform.pk8 app-debug.apk ControlCenter_signed.apk
文件目录:
signapk.jar: android/out/host/linux-x86/framework/signapk.jar
另外两个文件在 android/build/target/product/security/
除了platform签名以后还有 testkey  media  shared releasekey。
系统级别的签名使用的是platform来签名( 此时使用android:sharedUserId="android.uid.system"才有用 )。
但是使用的时候要注意,一定要使用和目标系统匹配的文件来签名
比如我的源码目中有两组platform签名的文件,我第一次签名搞错了(我没发现有另一组在devices目录下的文件),所有才有了后面两种方法的尝试。
之后我重新尝试另一组签名文件,签名成功后是可以符合期望工作的。

2.  不带源码直接放apk,mm编译

其实这一步也可以叫做“ 预置不带源码的apk ”。
1) 使用这种方法我们要为apk新建一个目录(一般自己的应用预置在packages/apps目录下,三方的可能在Vendor/third-party下),
2) 把apk放到目录下
3) 编写一个对应的Android.mk文件。
这里我们以googel translate.apk的预置为例,并以这个为参考编写我们自己的Android.mk。
下面是Translate目录下的Android.mk部分内容:
     
     
     
     
  1. # Translate
  2. LOCAL_PATH := $(call my-dir)
  3. include $(CLEAR_VARS)
  4. # Module name should match apk name to be installed
  5. LOCAL_MODULE := Translate
  6. LOCAL_MODULE_TAGS := optional
  7. LOCAL_SRC_FILES := $(LOCAL_MODULE).apk
  8. LOCAL_MODULE_CLASS := APPS
  9. LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX)
  10. LOCAL_CERTIFICATE := PRESIGNED
  11. LOCAL_BUILT_MODULE_STEM := package.apk
  12. include $(BUILD_PREBUILT)
这里LOCAL_CERTIFICATE := PRESIGNED,表示保留原签名,如果我们想让apk拥有和系统一样的签名则需要改成
     
     
     
     
  1. LOCAL_CERTIFICATE := platform
  2. LOCAL_PRIVILEGED_MODULE := true
4)之后在目录下mm编译。把生成的文件push到手机上就可以用了。
5)目前为止我们只是拿到系统应用的权限,如果需要在整包编译的时候把这个apk也编译进去的话,需要修改对应的编译系统的.mk文件,添加这个模块
     
     
     
     
  1. PRODUCT_PACKAGES += \
  2. Books \
  3. Bugle \
  4. GoogleCamera \

3. 带源码mm编译

加入现在已经有一个 使用Android Studio编写的app了,我们想要把它的源码放到Android系统目录下编译,该如何做呢?
1) 跟2差不多,还是先建目录已packages/app/目录下面为例,新建一个ControlCenter的目录,
2) 然后把源码全部放进去,然后把AndroidMainfest.xml复制到根目录。
如果不做清理的话,目录就是这个样子的

这里提醒一下,如果要保持Android Studio Project的目录格式的话,在用mm编译前要把build目录,test和androidTest目录删掉才能成功编译。
如果有强迫症的话也可以删除其他文件,改成下面的样子。

是不是简洁了很多?
但是上面那种有个好处,既可以mm编译,又可以单独用Android Studio编译。看自己需求。
3) 新建Android.mk文件。贴一下Android.mk文件内容:
    
    
    
    
  1. LOCAL_PATH:= $(call my-dir)
  2. include $(CLEAR_VARS)
  3. LOCAL_MODULE_TAGS := optional
  4. LOCAL_SRC_FILES := $(call all-subdir-java-files)
  5. #将res移动到这个应用的根目录
  6. #LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
  7. #如果你是Android Studio的res目录
  8. LOCAL_RESOURCE_DIR+= $(LOCAL_PATH)/app/src/main/res
  9. #apk名字
  10. LOCAL_PACKAGE_NAME := ControlCenter
  11. #系统签名
  12. LOCAL_CERTIFICATE := platform
  13. #如果有使用到依赖
  14. LOCAL_STATIC_JAVA_LIBRARIES:= \
  15. android-support-v4
  16. LOCAL_PRIVILEGED_MODULE := true
  17. include $(BUILD_PACKAGE)
mm/mma编译
4)同样如果编整包的时候把这个也编译进去,要修改对应的.mk文件。
因为我只是写了个简单的demo,jni和lib等不在本次讨论之列。

期间遇到的问题

mm编译不过
错误提示:
    
    
    
    
  1. packages/apps/ControlCenter/res/layout/activity_main.xml:14: error: Error: This attribute must be localized. (at 'text' with value 'wifi').
对应的代码:
    
    
    
    
  1. <Switch
  2. android:id="@+id/switch_wifi"
  3. android:layout_width="wrap_content"
  4. android:layout_height="wrap_content"
  5. android:layout_weight="1"
  6. android:text="wifi"
  7. android:onClick="onSwitchClicked" />
居然不允许直接使用字符,修改成@string后编译正常了。

总结

到此为止我们的需求已经通过三种方法实现了。
在有签名文件的情况下第一种方法最快捷。
第二种方法适合没有源码的情况,或者app已经稳定不需要修改的情况下。而且可以预置到系统中。
第三种方法适合有源码,而且这个app可能随时调整的情况。

扩展

一些Android.mk参数说明:

LOCAL_PATH:= $(call my-dir)
一个Android.mk file首先必须定义好LOCAL_PATH变量。它用于在开发树中查找源文件。
宏函数’my-dir’,由编译系统提供,用于返回当前路径(即包含Android.mk file文件的目录)。

#begin 在加入这个宏之前apk在/system/app下
#LOCAL_PRIVILEGED_MODULE := true 
#end 加入后apk在/system/priv-app下

#这个宏控制的是apk可卸载,恢复出厂设置后无法恢复
#LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)

#这个宏控制系统给apk签名
LOCAL_CERTIFICATE := PRESIGNED

#这个宏控制的是apk可卸载,恢复出厂设置后可以恢复
LOCAL_MODULE_PATH := $(TARGET_OUT)/vendor/operator/app

Android.mk中可以定义多个编译模块,每个编译模块都是以include $(CLEAR_VARS)开始,以include $(BUILD_XXX)结束(详解参考文末第二个链接)。

LOCAL_MODULE_TAGS := optional
解析:
LOCAL_MODULE_TAGS :=user eng tests optional
user:  指该模块只在user版本下才编译
eng:  指该模块只在eng版本下才编译
tests: 指该模块只在tests版本下才编译
optional:指该模块在所有版本下都编译
取值范围debug eng tests optional samples shell_ash shell_mksh。注意不能取值user,如果要预装,则应定义core.mk。


参考:

1. Android.mk文件格式  http://blog.csdn.net/demon_xiaochunjie/article/details/50052509
2. Android.mk简单分析  http://www.cnblogs.com/chenbin7/archive/2013/01/05/2846863.html (讲解了哪些是必选项,哪些是可选项)
3. Android.mk编译APK范例   http://hubingforever.blog.163.com/blog/static/1710405792011656434982/ (编译各种apk的举例)
4. 带有源码的apk预置到系统 http://blog.csdn.net/u013377887/article/details/53870803

推荐阅读

1. Android.mk简介    http://hubingforever.blog.163.com/blog/static/171040579201152185542166/
2. Android.mk文件语法规范(Android.mk File) http://blog.csdn.net/smfwuxiao/article/details/8530742 (NDK jni)
3. Android.mk文件语法规范 & 使用模板  http://www.cnblogs.com/jisheng/archive/2012/09/13/2683057.html (这是个译文,也有很多参数的解释)




你可能感兴趣的:(源码,签名,编译,系统应用,预置)