預置第三方apk到MTK項目相關問題總結
版權聲明:本文為博主原創文章,未經博主允許不得轉載。
目錄(?)[+]
標籤:MTK 預置apk
作者:解國棟 2015-06-03
目前5.0之後項目預置方式通用步驟為:建立apk文件夾; 置目標apk到該文件夾下; 解壓縮apk查看是否包含lib/文件夾(apk項目是否包含lib庫文件); 在該文件夾下編寫Android.mk腳本 ;
理論上apk文件夾可以建立在項目內任意目錄,編譯系統會自動搜索並根據其內Android.mk(編譯腳本)來進行編譯。編譯系統採用的是遞歸搜索,在搜索到父文件目錄的Android.mk腳本後遞歸便被終止。因此一般可以將需要預置的apk文件夾放到一個總文件夾內,並在該文件夾根目錄另外寫一個Android.mk(管理腳本),以便對所有預置apk進行管理。對於管理腳本的編寫將在文末解釋。預置目錄如下例:
Apps/-/Android.mk管理腳本-/Test1—-/Android.mk編譯腳本—-/Test1.apk—-/lib/*-/Test2—-/Android.mk編譯腳本—-/Test2.apk—-/lib/*…
編譯腳本如下例:LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE := TestLOCAL_MODULE_CLASS := APPSLOCAL_MODULE_TAGS := optionalLOCAL_BUILT_MODULE_STEM := package.apkLOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX)LOCAL_CERTIFICATE := PRESIGNEDLOCAL_SRC_FILES := Test_*.apkinclude $(BUILD_PREBUILT)
其中,LOCAL_MODULE := Test
表示了一個預置的apk在編譯中的唯一標識,同時編譯後該apk會以此命名;LOCAL_SRC_FILES := Test_*.apk
表示了當前要預置的apk的文件名,」Test_*.apk」匹配任意以」Test_」開頭的apk文件。
對於apk預置路徑,在Android.mk中可以通過以下方式指名:
a)默認預置apk到system/app/目錄(普通系統apk,不可卸載),如前文Android.mk腳本編寫之後即可;b)預置apk到system/priv-app/目錄(系統核心apk,不可卸載),在前文Android.mk腳本中添加並配置變數:
LOCAL_PRIVILEGED_MODULE := true
c)預置apk到data/app/目錄並且卸載後不需要再會恢復,在前文Android.mk腳本中配置變數:
LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
d)預置apk到data/app/目錄並且卸載後恢復出廠可以恢復,在前文Android.mk簡本中配置變數:
LOCAL_MODULE_PATH := $(TARGET_OUT)/vendor/operator/app
對於包含lib庫文件的apk,還需要根據預置目標路徑,在mk腳本中作不同的處理:
情況一:對於預置到data/app/目錄下的apk,包括可恢復和不可恢復(即上一段c)和d)), 一般lib庫文件可以不用手動添加,apk在首次運行時,會自動將自身的lib庫抽取安裝到自身的根目錄;情況二:對於預置到system/app/ 和 system/priv-app 目錄下的apk(即上一段a)和b)),因為在android系統中,system分區是不允許應用執行寫操作的,因此需要在Android.mk腳本中進行配置,手動添加lib庫文件到編譯環境,以便lib庫文件在編譯之後拷貝到對應編譯後的apk目錄下,否則apk執行時會因找不到lib庫而報錯;
<一>、首先根據情況二所述,添加lib庫文件到編譯環境方法一不從apk中解壓lib庫而直接添加
如下例,在Android.mk中添加並配置變數(注意路徑對應):
LOCAL_PREBUILT_JNI_LIBS = @lib/armeabi-v7a/libcryptox.so @lib/armeabi-v7a/libfb.so
注意前面的@
符號,@標識符會將apk中的so抽離出來,拷貝到對應編譯後的apk目錄;
方法二手動解壓lib文件到當前apk的編譯目錄並添加
先解壓當前apk內的lib文件夾到當前apk編譯目錄,同方法一在Android.mk中添加並配置變數(注意路徑對應),如下例:
LOCAL_PREBUILT_JNI_LIBS = lib/armeabi-v7a/libcryptox.so lib/armeabi-v7a/libfb.so
若當前apk包含的lib庫文件數量比較多時,上述代碼可以通過修改為如下代碼進行優化,優化的思路是用遞歸搜索來替代手工對lib庫文件進行添加:
###清空臨時變數JNI_LIBS JNI_LIBS :=###當前目錄遞歸搜索$(foreach FILE,$(shell find $(LOCAL_PATH)/lib/ -name *.so), $(eval JNI_LIBS += $(FILE)))###獲取搜索文件目錄集(相對目錄)LOCAL_PREBUILT_JNI_LIBS := $(subst $(LOCAL_PATH),,$(JNI_LIBS))
<二>、然後需要注意當前Android環境是否符合apk運行條件(64位和32位)並配置apk運行環境
之所以要配置apk運行環境,是因為包含lib庫的apk在添加lib庫到編譯環境之後,在Android環境和apk運行條件不符的情況下,需要在編譯環境中指定環境。舉例說明:
目前一般的apk運行環境為32位Android系統環境,當在64位Android系統中預置帶有lib庫的apk時,手動添加lib庫文件到編譯環境後,默認情況下編譯環境會在編譯後apk目錄建立64位的環境的lib庫路徑/lib/arm64
,雖然編譯過程未報錯,但之後在執行該apk時,會出現apk因找不到lib庫而報錯
因此,需要在Android.mk中對當前apk編譯環境進行配置,配置的方法常見的也有兩種:
<1>指定編譯目標為32位或64位
在Android目標中添加並配置變數:
LOCAL_MULTILIB := ###可選值 /32/64/first/both
不同的值含義如下:
「both」:build both 32-bit and 64-bit. 「32」:build only 32-bit.> *「64」:build only 64-bit. 「first」:build for only the first arch (32-bit in 32-bit devices and 64-bit in 64-bit devices). 「」:the default; the build system decides what arch to build based on the module class and other LOCAL_ variables, such as LOCAL_MODULE_TARGET_ARCH, LOCAL_32_BIT_ONLY, etc.
此處,default
值會根據當前已有的其他相關值方式來進行編譯
<2>指定目標lib庫的類型在Android.mk中添加並配置變數:
LOCAL_MODULE_TARGET_ARCH := ###可選值 arm/arm x86/arm64
此處,LOCAL_MODULE_TARGET_ARCH
的值只能是當前編譯環境所支持的類型,如果需要配置當前系統不支持類型,則需要配置如下另一個變數
LOCAL_MODULE_UNSUPPORTED_TARGET_ARCH := ###可選值 arm/arm x86/arm64
與LOCAL_MODULE_TARGET_ARCH
相反,LOCAL_MODULE_UNSUPPORTED_TARGET_ARCH
的值只能是當前編譯環境所不支持的類型,否則編譯將不會生效
如下是一個完整的Android.mk腳本示例,其中apk運行環境為32位,系統為64位:
LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE := UCBrowserLOCAL_MODULE_CLASS := APPSLOCAL_MODULE_TAGS := optionalLOCAL_BUILT_MODULE_STEM := package.apkLOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX)LOCAL_CERTIFICATE := PRESIGNEDLOCAL_SRC_FILES := HK_UCBrowser*.apkLOCAL_PRIVILEGED_MODULE := trueLOCAL_MULTILIB := 32JNI_LIBS :=$(foreach FILE,$(shell find $(LOCAL_PATH)/lib/ -name *.so), $(eval JNI_LIBS += $(FILE)))LOCAL_PREBUILT_JNI_LIBS := $(subst $(LOCAL_PATH),,$(JNI_LIBS))include $(BUILD_PREBUILT)
最後編寫管理腳本集中管理預置apk
預置三方apk一般根據客戶項目的不同而有所差異,因此如前文所述,可以將需要預置的apk文件夾放到一個總文件夾內,該文件夾可以採用與客戶項目有關的命名用以區分不同客戶項目預置,並在該文件夾根目錄另外寫一個Android.mk(管理腳本), 這樣便可以根據客戶項目對預置apk進行管理。以下是據此更新後的預置目錄,具體可以根據原理自行調整:
Customer1/-/Android.mk管理腳本-/Test1—-/Android.mk編譯腳本—-/Test1.apk—-/lib/*-/Test2—-/Android.mk編譯腳本—-/Test2.apk—-/lib/*Customer2/-/Android.mk管理腳本-/Test3—-/Android.mk編譯腳本—-/Test1.apk—-/lib/*-/Test4—-/Android.mk編譯腳本—-/Test2.apk—-/lib/*…
對於管理腳的編寫,如下例:
LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)###此處也可以在此添加一個宏變數來控制是否執行以下代碼###if($(strip $(XXX_CUSTOMER1_APP)),yes))SUB_ANDROID_MK := $(shell find $(LOCAL_PATH)/apps/ -name Android.mk)$(foreach sub_mk,$(SUB_ANDROID_MK), $(eval include $(sub_mk)))PRODUCT_PACKAGES += Test1Test2###endif
其中$(shell find $(LOCAL_PATH)/apps/ -name Android.mk)
返回一個遍歷搜索子目錄 Android.mk 的路徑集合,此處也可以採用手動添加指定路徑的方式來控制具體預置的apk是否編譯 :
###替換###SUB_ANDROID_MK := $(shell find $(LOCAL_PATH)/apps/ -name Android.mk)###$(foreach sub_mk,$(SUB_ANDROID_MK), $(eval include $(sub_mk)))###為include Customer1/Test1/Android.mkinclude Customer1/Test2/Android.mk
同時,PRODUCT_PACKAGES
變數指定將哪些編譯完成的apk 打包到項目最終編譯生成的Android系統鏡像文件中,如上代碼中,其值恰恰就是預置apk的編譯腳本中定義的LOCAL_MODULE
(即編譯後該apk的名稱)的值
推薦閱讀:
※普利法會功德項目
※尿常規檢查項目有哪些
※神秘的2999元收費項目課程被我這樣破解了...
※新交規記分項目詳解
※檔案實務|國家檔案局付華副局長如何看待InterPARES項目對中國的意義?