android源码编译apk集成第三方so库

一般编译android应用,生成apk,有以下几个方法:

    1.传统的在eclipse平台下编译生成apk,这种情况下,需要指定android sdk,通过eclipse编译生成apk,编译的apk拥有较低级别的用户级别权限,可能有些底层操作没有权限实现,比如部分system调用,访问系统文件目录等。如果存在jni调用,则需要创建jni目录,并在jni目录里面创建android.mk,通过ndk编译生成动态库.so供上层调用,生成的动态库必须放在libs/armeabi或者libs/armeabli-v7a目录下面,在eclipse打包时候才能将.so打包到apk中,安装此apk,会安装到/data/app目录下,同时将apk和so文件写入/data/相应目录下,表示安装成功。

    2.如果需要生成apk拥有system权限,则需要在AndroidManifest.xml中指定android.sharedUserId="android.uid.system"里获取system权限,同时在生成apk后要进行签名,签名命令类似如下格式:

    java -jar signapk.jar platform.x509.pem platform.pk8 old.apk new.apk 

  这样生成的apk会比1中生成的apk拥有较高级别的权限。platform.x509.pem platform.pk8这两个文件一般在所在android源码系统中的build\target\product\security目录下面,signapk.jar为一个签名工具,一般在源码out/hostlinux-x86/framework/signapk.jar 目录下面。


  3.无论1和2,android应用均只能调用开放的SDK中api或者属性参数,由于SDK是android framework的一个子集,有大量framework中的api或者属性并没有开放给SDK,因此android上层应用无法调用。如果想调用framework中的一些未开放到SDK的api,同时要求apk拥有系统级权限,那么只能将android应用放到源码里进行编译。我将android应用放到android源码中的packages/apps/中,通过mmm命令来编译,这些应用可以调用framework的api并拥有系统级权限,生成的apk在out/target/product/dt307sq/system/app/下,dt307sq是硬件平台名称。packages/apps/下有大量系统级应用,这些应用在源码编译的时候会随源码一起编译,随系统一起安装,安装在系统/system/app下,这些系统级应用可以作为我们的参考。对于牵涉到了jni调用的情况,同方法1,必须编译出.so库,才能编译成功。比如源码里面有个Bluetooth的例子,其目录结构为


Android.mk内容如下:

LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)


LOCAL_MODULE_TAGS := optional


LOCAL_SRC_FILES := \
        $(call all-java-files-under, src)


LOCAL_PACKAGE_NAME := Bluetooth
LOCAL_CERTIFICATE := platform


LOCAL_JNI_SHARED_LIBRARIES := libbluetooth_jni
LOCAL_JAVA_LIBRARIES := javax.obex
LOCAL_STATIC_JAVA_LIBRARIES := com.android.vcard


LOCAL_REQUIRED_MODULES := libbluetooth_jni bluetooth.default


LOCAL_PROGUARD_ENABLED := disabled


include $(BUILD_PACKAGE)


include $(call all-makefiles-under,$(LOCAL_PATH))

LOCAL_JNI_SHARED_LIBRARIES := libbluetooth_jni表示该apk依赖libbluetooth_jni这个模块,这个模块的编译脚本在jni目录下:

LOCAL_PATH := $(call my-dir)


include $(CLEAR_VARS)


LOCAL_SRC_FILES:= \
    com_android_bluetooth_btservice_AdapterService.cpp \
    com_android_bluetooth_hfp.cpp \
    com_android_bluetooth_a2dp.cpp \
    com_android_bluetooth_hid.cpp \
    com_android_bluetooth_hdp.cpp \
    com_android_bluetooth_pan.cpp


LOCAL_C_INCLUDES += \
    $(JNI_H_INCLUDE) \


LOCAL_SHARED_LIBRARIES := \
    libandroid_runtime \
    libnativehelper \
    libcutils \
    libutils \
    libhardware


#LOCAL_CFLAGS += -O0 -g


LOCAL_MODULE := libbluetooth_jni
LOCAL_MODULE_TAGS := optional


include $(BUILD_SHARED_LIBRARY)

这个生成libbluetooth_jni.so


这样通过mmm编译的apk包含进了.so库。


但有这样一种情况,.so库是在外面通过android ndk编译生成的,没有在源码里面编译,这个就是第三方库,那么如何将.so库打到apk里面呢。刚开始,我想到一个办法。将.so文件放到/lib/armeabi/这个目录里面,然后再通过mmm编译生成apk,但发现apk里面根本没有lib这个目录。后来我又尝试另外一种方法:

改下android.mk如下:

LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)


LOCAL_STATIC_JAVA_LIBRARIES:= xstream
LOCAL_STATIC_LIBRARIES:= libnative-backendservice-jni
LOCAL_MODULE_TAGS := optional


LOCAL_SRC_FILES += $(call all-java-files-under, src)
LOCAL_SRC_FILES += $(call all-java-files-under,gen)


LOCAL_PACKAGE_NAME := ClientAgent
LOCAL_CERTIFICATE := platform


#LOCAL_PROGUARD_NEALBED: = false
#LOCAL_PROGUARD_FLAG_FILES := proguard.cfg


include $(BUILD_PACKAGE)


include $(CLEAR_VARS)
LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES:=xstream:lib/xstream-1.4.4.jar
include $(BUILD_MULTI_PREBUILT)


include $(CLEAR_VARS)
LOCAL_PREBUILT_LIBS:=libnative-backendservice-jni:lib/armeabi/libnative-backendservice-jni.so
include $(BUILD_MULTI_PREBUILT)




# Use the folloing include to make our test apk.
#include $(call all-makefiles-under,$(LOCAL_PATH))


这种方法通过include $(BUILD_MULTI_PREBUILT)集成第三方库,但发现这种方法只是在编译apk的时候,将第三方库自动拷贝到out/target/product/dt307sq/system/lib下,根本没有在apk里面打包第三方.so库。

最终发现以下办法能将第三方库打包到源码编译的apk中。


1).将第三方库.so放到应用下的lib/armeabi中

2).通过mmm编译出apk,这个apk里面没有包含lib目录

3).通过aapt命令,添加lib/armeabi里的.so库,例如:./aapt a ../../../out/target/product/dt307sq/system/app/ClientAgent.apk lib/armeabi/libnative-backendservice-jni.so

aapt命令在源码out/host/linux-x86/bin下,是很强大的工具,注意一定要带lib/armeabi/目录,apk会根据名称生成对应的目录

4).最后签名,例如:java -jar signapk.jar platform.x509.pem platform.pk8 ../../../out/target/product/dt307sq/system/app/ClientAgent.apk ClientAgentSign.apk

生成的apk,具有系统级权限,在源码里编译生成的,同时需要调用的jni动态库是在源码外面通过android ndk编译生成的。


一般情况下,需要在源码里编译,最好android应用和jni动态库部分都通过源码来编译,这是最好的方法。但是有些情况下,需要调用大量第三方库,因为源码编译环境下,这些第三方库不一定能编译通过,那就只能在外面编译好了,然后加到源码编译生成的apk中。

发布了137 篇原创文章 · 获赞 110 · 访问量 46万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章