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萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章