Android.mk文件学习,将工程编译到系统中(实践篇)

前言

千呼万唤使出来,答应的事儿一定做到;之前在一篇文章中说到自己会出一篇比较详细介绍Android.mk文件的文章,一言既出,必须得出!本文主要是介绍一些比较常用的mk文件里面的标签使用,同时也给出一些使用实例供大家做模板参考使用,话不多说,上小菜儿!

正文

本文是基于本人测试使用的一个demo来说明android.mk文件属性,我觉得用实例说话会让人更加理解其含义,所以自己写了一个比较全的工程来自写android.mk文件,先把使用的工程demo文件目录列一下吧:
工程目录1
工程目录2
这个demo覆盖了Android工程里面比较常用的,包括jar包/lib库/jni/aidl,先上我自己写好跑过的Android.mk文件:

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
#编译源文件 声明需要编译的文件类型
LOCAL_SRC_FILES := $(call all-subdir-java-files)
#另外注意,这条语句必须加入到最后面出现LOCAL_SRC_FILES位置后面,否则会无效。
LOCAL_SRC_FILES += src/com/topwise/cloudpos/aidl/AidlDeviceService.aidl \
                   src/com/topwise/cloudpos/aidl/emv/AidlCheckCardListener.aidl \
                   src/com/topwise/cloudpos/aidl/emv/AidlPboc.aidl \
                   src/com/topwise/cloudpos/aidl/emv/AidlPbocStartListener.aidl
#编译的标签 默认为optional
LOCAL_MODULE_TAGS := optional
#签署当前应用的证书名称
LOCAL_CERTIFICATE := platform
#编译生成的apk名称
LOCAL_PACKAGE_NAME := TOPUSDKServiceMk
#指定是否启用混淆 
#如果要开混淆 需要同LOCAL_PROGUARD_FLAG_FILES这个属性一起用
LOCAL_PROGUARD_ENABLED := disabled
#编译的静态库
LOCAL_STATIC_JAVA_LIBRARIES := libbcprov_jdk libcore libsc_light_jdk15on
LOCAL_STATIC_JAVA_LIBRARIES += android-support-v4 \
                               android-support-v7-appcompat
#依赖的so文件若在lib下没有,则找makefile文件编译 load库的时候去掉lib
LOCAL_REQUIRED_MODULES := libposdevice libemvtopwise

#编译apk结尾
include $(BUILD_PACKAGE)

####预编译模块 --start--
include $(CLEAR_VARS)   
#预编译导入的静态库(jar包)
LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES :=libbcprov_jdk:libs/bcprov-jdk16-145.jar \
                                       libcore:libs/core_3.3.0.jar \
                                       libsc_light_jdk15on:libs/sc-light-jdk15on-1.47.0.2.jar
#libemv_jni:libs/armeabi/libemvtopwise.so 预编译成libemv_jni.so
#libs/armeabi/libzbar.so 预编译成libzbar.so
LOCAL_PREBUILT_LIBS := libs/armeabi/libzbar.so \
                       libs/armeabi/libDCL.so
LOCAL_MODULE_TAGS := optional  
include $(BUILD_MULTI_PREBUILT)  
####预编译模块 --end--

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

首先基本的Android.mk文件开始先要定义工程路径,LOCAL_PATH字段定义工程路径,之后清除编译定义变量:

//$(call my-dir)返回当前Android.mk文件所在文件夹
LOCAL_PATH := $(call my-dir)
//清除之前定义的变量值
include $(CLEAR_VARS)

后面的标签一个一个说明:

LOCAL_SRC_FILES :用来定义需要编译的源文件,这里要注意的是aidl文件需放在所有添加源文件之后,也就是要末尾定义;
这里列举几个常用的获取源文件的方法(获取指定目录下的文件,不包含子文件夹下的)
$(call all-java-files-under, src):获取指定目录下的所有 Java 文件。
$(call all-c-files-under, src):获取指定目录下的所有 C 语言文件。
$(call all-Iaidl-files-under, src) :获取指定目录下的所有 AIDL 文件。
$(call all-makefiles-under, folder):获取指定目录下的所有 Make 文件。

LOCAL_MODULE_TAGS:用于说明编译条件;常用的有:debug, eng, user,development 或者 optional。其中,optional 是默认标签。

LOCAL_CERTIFICATE:用于说明签名属性,指需要那种签名文件签名;常用的有:
1、testkey:普通APK,默认情况下使用。 2、platform:该APK完成一些系统的核心功能。经过对系统中存在的文件夹的访问测试,这种方式编译出来的APK所在进程的UID为system。3、shared:该APK需要和home/contacts进程共享数据。4、media:该APK是media/download系统中的一环。

LOCAL_PACKAGE_NAME:编译生成的apk名称;如果你编译的是PACKAGE,那么模块说明就用这个标签。

LOCAL_PROGUARD_ENABLED:是否开启混淆;默认情况下是开混淆的,如果你想自定义混淆规则,可同LOCAL_PROGUARD_FLAG_FILES这个属性一起用。

LOCAL_PROGUARD_FLAG_FILES:定义混淆文件;将混淆文件(+路径)加到此标签后即可。

LOCAL_STATIC_JAVA_LIBRARIES:静态库文件;需要编译到module模块里的库文件需在此标签定义。一般包含AndroidOS库(v4 v7包等)和预编译静态库文件(jar包等);这里跟的是库标签名称,非本库路径。

LOCAL_SHARED_LIBRARIES:动态库文件,一般都具有依赖性;一般为预编译库或者已存在的三方库,无此库的时候先去编译此库;

LOCAL_REQUIRED_MODULES:该模块运行所依赖的模块文件;其中jni代码的编译module就放到这里,libposdevice/libemvtopwise这两个定义是在jni的mk文件定义的module名称,具体见下文;

include $(BUILD_PACKAGE):编译PACKAGE包结尾说明,表示编译成APK包,其他的还有:
include $(BUILD_STATIC_LIBRARY) 表示编译成静态库
include $(BUILD_SHARED_LIBRARY) 表示编译成动态库
include $(BUILD_EXECUTABLE) 表示编译成可执行程序
include $(BUILD_STATIC_JAVA_LIBRARY) 编译成Java静态库
include $(BUILD_MULTI_PREBUILT) 会将prebuild的那些,还有required那些库拷到本地来编译

如果工程中有jar包或者本地库等,需先预编译之后方可编译或者连接,以下就是预编译模块代码:代码块

####预编译模块 --start--
include $(CLEAR_VARS)   
#预编译导入的静态库(jar包)
LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES :=libbcprov_jdk:libs/bcprov-jdk16-145.jar \
                                       libcore:libs/core_3.3.0.jar \
                                       libsc_light_jdk15on:libs/sc-light-jdk15on-1.47.0.2.jar
#libemv_jni:libs/armeabi/libemvtopwise.so 预编译成libemv_jni.so
#libs/armeabi/libzbar.so 预编译成libzbar.so
LOCAL_PREBUILT_LIBS := libs/armeabi/libzbar.so \
                       libs/armeabi/libDCL.so
LOCAL_MODULE_TAGS := optional  
include $(BUILD_MULTI_PREBUILT)  
####预编译模块 --end--

LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES:预编译静态库;这里是因为jar包需要打包编译到APK中,所以jar包要编译成静态库;编译静态库前面最好加重定义(libbcprov_jdk),这样在模块编译的时候LOCAL_STATIC_JAVA_LIBRARIES下方便进行引用;
LOCAL_PREBUILT_LIBS:预编译动态库;本地库需先预编译为动态库,才可成功连接到APK。
ps:预编译库的时候需注意重定义库名称的使用,防止代码中loadLibrary时引用名称错误;例如如果LOCAL_PREBUILT_LIBS := libemv_jni:libs/armeabi/libemvtopwise.so,编译出的库名称为 libemv_jni.so,但LOCAL_PREBUILT_LIBS := libs/armeabi/libemvtopwise.so,编译出的库名称为libemvtopwise.so;
后面两个属性前面有说明;

include $ (call all-makefiles-under,$(LOCAL_PATH)):此行意思是如果当前mk文件编译完成,递归查找子目录下的mk文件并编译;如果编译jni,此行必出现。

OK,你可以结合上面贴的工程目录树形图和mk文件一一对照,看如何定义各个标签;其中jni的mk文件也贴出如下:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)
#编译生成模块名称 编译出来会自带格式:***.so 
#跟AS编译出来不一样 AS自带格式:lib***.so
LOCAL_MODULE    := libposdevice
LOCAL_SRC_FILES := com_android_topwise_sdk_jni_PosDevice.cpp
LOCAL_SRC_FILES += posdevice.cpp
#理解是链接系统库所用
LOCAL_LDLIBS := -llog
include $(BUILD_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE    := libemvtopwise
LOCAL_SRC_FILES += emv/com_android_topwise_sdk_jni_EmvJNI.c
LOCAL_SRC_FILES += emv/jni_util.c
LOCAL_LDLIBS := -llog
#链接共享库 一般为预编译库或者已存在的三方库
#有依赖关系 没有此库时编译此库
LOCAL_SHARED_LIBRARIES += libtop_emv
include $(BUILD_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_PREBUILT_LIBS := libtop_emv:lib32/libtopemv.so
include $(BUILD_MULTI_PREBUILT)

这里的标签基本在上文都有解释,其中:

LOCAL_LDLIBS := -llog
链接的库不产生依赖关系,一般用于不需要重新编译的库,如库不存在,则会报错找不到。且貌似只能链接那些存在于系统目录下本模块需要连接的库;例如常用的有: -lm –lz –lc -lcutils –lutils –llog;

目前预编译动态库进行局部编译后都会拷贝到系统system/lib目录下的(platform),没有编译到APK内部,所以如果调试过程中想运行编译出的APK,需将编译生成的动态库push到system/lib下调试运行!

OK,到这里基本Android.mk文件就写完了,接下来说说我碰到的钉子以及介绍下其他相关内容吧!

aidl编译过程遇到的障碍:

  1. aidl使用自定义类(实现序列化接口)作为参数注意,首先构造一个类CardInfo.java:代码块
package com.topwise.cloudpos.aidl.emv;

import android.os.Parcel;
import android.os.Parcelable;

/**
 * 卡数据bean
 * 
 * @author xk
 * 
 */
public class CardInfo implements Parcelable {

	private String cardno = null;
	public CardInfo(Parcel source) {
		this.cardno = source.readString();
	}
	public CardInfo(String cardno){
		this.cardno = cardno;
	}
	@Override
	public int describeContents() {
		// TODO Auto-generated method stub
		return 0;
	}
	public String getCardno() {
		return cardno;
	}
	public void setCardno(String cardno) {
		this.cardno = cardno;
	}
	public static Creator<CardInfo> getCreator() {
		return CREATOR;
	}

	@Override
	public void writeToParcel(Parcel dest, int flags) {
		dest.writeString(this.cardno);
	}

	public static final Creator<CardInfo> CREATOR = new Creator<CardInfo>() {

		@Override
		public CardInfo createFromParcel(Parcel source) {
			// TODO Auto-generated method stub
			CardInfo cardno = new CardInfo(source);
			return cardno;
		}

		@Override
		public CardInfo[] newArray(int size) {
			// TODO Auto-generated method stub
			return new CardInfo[size];
		}
	};
}

再定义一个同名的aidl文件CardInfo.aidl,代码块

package com.topwise.cloudpos.aidl.emv;
parcelable CardInfo;

之后才可在aidl接口中使用它作为参数;代码块

package com.topwise.cloudpos.aidl.emv;
import com.topwise.cloudpos.aidl.emv.CardInfo;
interface AidlPbocStartListener{
    / ...
      ... /
	void onConfirmCardInfo(in CardInfo cardInfo);
}

在LOCAL_SRC_FILES中添加编译文件时无需把CardInfo.aidl列入,编译时会自动取文件进行编译!

  1. 在使用Bundle/Bitmap等作为参数时,如果你是在系统代码中创建的工程,需import声明;如果是AS中创建则不需要;

动态库和静态库的区别

一句话,动态库是运行时加载(.so),静态库是编译时加载(.a),当两者同时存在且同名时,优先使用动态库加载;
具体解释可参考链接:https://blog.csdn.net/zzcchunter/article/details/88995492

编译APK文件到系统时mk文件参考

LOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE := USDKService
LOCAL_MODULE_TAGS := optional 
LOCAL_SRC_FILES := USDKService.apk
#编译中间暂存目录
LOCAL_MODULE_CLASS := APPS
#后缀名称,使用默认
LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX)
LOCAL_CERTIFICATE := platform

include $(BUILD_PREBUILT)

局编过程遇到的问题汇总

  1. ninja: error: ‘out/target/product/tpw8735b_t3h/obj/SHARED_LIBRARIES/lib32/libtopemv.so_intermediates/export_includes’,
    needed by ‘out/target/product/tpw8735b_t3h/obj/SHARED_LIBRARIES/emvtopwise_intermediates/import_includes’,
    missing and no known rule to make it

解决方法:jni预编译库出错 使用BUILD_MULTI_PREBUILT,此类问题一般都是预编译出错,仔细检查预编译的相关代码;

include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_PREBUILT_LIBS := libtop_emv:lib32/libtopemv.so
include $(BUILD_MULTI_PREBUILT)
  1. No resource found that matches the given name 'Theme.AppCompat.Light.DarkActionBar
    解决方法:缺少库文件,导入V7包
LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4 
LOCAL_STATIC_JAVA_LIBRARIES += android-support-v7-appcompat 
LOCAL_STATIC_JAVA_LIBRARIES += android-support-v7-gridlayout 
LOCAL_STATIC_JAVA_LIBRARIES += android-support-v13

后记

稍微写一写就得一晚上时间,又熬夜了~唉~
本文只是介绍了一些android.mk中常用的属性值,后续还会不停补充更新!若有写的不正确的地方,还请大佬们评论指正,谢谢!

  • 3
    点赞
  • 15
    收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:深蓝海洋 设计师:CSDN官方博客 返回首页
评论

打赏作者

狗仔儿

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值