预置第三方apk到MTK项目相关问题总结

来源:互联网 发布:南通java培训班 编辑:程序博客网 时间:2024/05/18 00:35

目前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)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

其中,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
  • 1
  • 1

c) 预置apk到data/app/目录并且卸载后不需要再会恢复,在前文Android.mk脚本中配置变量:

LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
  • 1
  • 1

d) 预置apk到data/app/目录并且卸载后恢复出厂可以恢复,在前文Android.mk简本中配置变量:

LOCAL_MODULE_PATH := $(TARGET_OUT)/vendor/operator/app
  • 1
  • 1

对于包含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 
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

注意前面的 @符号,@标识符会将apk中的so抽离出来,拷贝到对应编译后的apk目录;

方法二 手动解压lib文件到当前apk的编译目录并添加

先解压当前apk内的lib文件夹到当前apk编译目录,同方法一在Android.mk中添加并配置变量(注意路径对应),如下例:

LOCAL_PREBUILT_JNI_LIBS = \lib/armeabi-v7a/libcryptox.so \lib/armeabi-v7a/libfb.so 
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

若当前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))
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

<二>、然后需要注意当前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 
  • 1
  • 2
  • 1
  • 2

不同的值含义如下:

  • “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
  • 1
  • 2
  • 1
  • 2

此处, LOCAL_MODULE_TARGET_ARCH 的值只能是当前编译环境所支持的类型,如果需要配置当前系统不支持类型,则需要配置如下另一个变量

LOCAL_MODULE_UNSUPPORTED_TARGET_ARCH := ###可选值 arm/arm x86/arm64
  • 1
  • 2
  • 1
  • 2

与 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)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

最后编写管理脚本集中管理预置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 += \Test1\Test2###endif
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

其中 $(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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

同时,PRODUCT_PACKAGES 变量指定将哪些编译完成的apk 打包到项目最终编译生成的Android系统镜像文件中,如上代码中,其值恰恰就是预置apk的编译脚本中定义的 LOCAL_MODULE (即编译后该apk的名称)的值。

1 0
原创粉丝点击