1.简介
1.Android.mk是一个向Android NDK构建系统描述NDK项目的GNU makefile片段。主要用来编译生成一下几种:
1.APK程序:一般的Android应用程序,系统级别的直接push即可。
2.JAVA库:JAVA类库,编译打包生成jar文件。
3.C\C++应用程序:可执行的C\C++应用程序。
4.C\C++静态库:编译生成C\C++静态库,并打包成.a文件。
5.C\C++共享库:编译生成共享库,并打包成.so文件。
2.案例
# 定义当前模块路径 (必须定义在文件开头,只需定义一次)
LOCAL_PATH := $(call my-dir)
# 清空当前环境变量 (LOCAL_PATH除外)
include $(CLEAR_VARS)
# 当前模块名 (这里会生成libhello-jni.so) 模块名必须唯一,不能包含空格
LOCAL_MODULE := hello-jni
# 当前模块包含的源代码文件 多个可以用空格隔开
LOCAL_SRC_FILES := hello-jni.c
# 生成一个动态库(表示当前模块被编译成一个共享库)
include $(BUILD_SHARED_LIBRARY)
3.编译多个共享库
一个Android.mk可能编译产生多个共享库模块,如下产生了libmodule1.so 和 libmodule2.so两个库
LOCAL_PATH := $(call my-dir)
#模块1
include $(CLEAR_VARS)
LOCAL_MODULE := module1
LOCAL_SRC_FILES := module1.c
include $(BUILD_SHARED_LIBRARY)
#模块2
include $(CLEAR_VARS)
LOCAL_MODULE := module2
LOCAL_SRC_FILES := module2.c
include $(BUILD_SHARED_LIBRARY)
4.编译静态库
Android应用程序不能直接使用静态库,但是静态库可以用来编译成动态库。比如在将第三方代码添加到原生项目中时,
可以不用直接将第三方源码包含在原生项目中,而是将第三方源码编译成静态库,然后并入共享库
LOCAL_PATH := $(call my-dir)
# 第三方库AVI
include $(CLEAR_VARS)
LOCAL_MODULE := AVI
LOCAL_SRC_FILES := AVI.c
include $(BUILD_STATIC_LIBRARY)
#原生模块
include $(CLEAR_VARS)
LOCAL_MODULE := module
LOCAL_SRC_FILES := module.c
#将静态库模块名添加到LOACAL_STATIC_LIBRARIES变量
LOCAL_STAITC_LIBRAYIES := AVI
include $(BUILD_SHARED_LIBRARY)
5.使用共享库共享通用模块
静态库可以保证源代码模块化,但是当静态库与共享库相连时,它就变成了共享库的一部分。在多个共享库的情况下,
多个共享库与静态库连接时,需要将通用模块的多个副本与不同的共享库重复相连,这样就增加了app的大小,这种
情况,可以将通用模块作为共享库。
LOCAL_PATH := $(call my-dir)
# 第三方库AVI
include $(CLEAR_VARS)
LOCAL_MODULE := AVI
LOCAL_SRC_FILES := AVI.c
include $(BUILD_SHARED_LIBRARY)
#原生模块1
include $(CLEAR_VARS)
LOCAL_MODULE := module1
LOCAL_SRC_FILES := module1.c
LOCAL_SHARED_LIBRARIES := AVI
include $(BUILD_SHARED_LIBRARY)
#原生模块2
include $(CLEAR_VARS)
LOCAL_MODULE := module2
LOCAL_SRC_FILES := module2.c
LOCAL_SHARED_LIBRARIES := AVI
include $(BUILD_SHARED_LIBRARY)
6.在多个NDK项目间共享模块
1.首先将AVI源代码移动到NDK项目以外的位置
2.作为共享模块,AVI需要有自己的Android.mk模块
3.以transcode/avilib为参数调用函数宏import-module添加到NDK项目的Android.mk文档末尾
#AVI模块自己的Android.mk文件
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := AVI
LOCAL_SRC_FILES := AVI.c
include $(BUILD_SHARED_LIBRARY)
#使用共享模块的NDK项目1的Android.mk文件
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := module1
LOCAL_SRC_FILES := module1.c
LOCAL_SAHRED_LIBRARIES := AVI
include $(BUILD_SHARED_LIBRARY)
$(call import-module, transcode/AVI)
#使用共享模块的NDK项目2的Android.mk文件
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := module2
LOCAL_SRC_FILES := module2.c
LOCAL_SAHRED_LIBRARIES := AVI
include $(BUILD_SHARED_LIBRARY)
$(call import-module, transcode/AVI)
7.使用预编译库
1.想在不发布源代码的情况下降模块发布给他人
2.想使用共享模块的预编译版来加速编译过程
#使用预编译共享模块的Android.mk文件
LOCAL_PATH := $(call my-dir)
#第三方预编译库
include $(CLEAR_VARS)
LOCAL_MODULE := AVI
LOCAL_SRC_FILES := libAVI.so
include $(PREBUILD_SHARED_LIBRARY)
8.编译独立的可执行文件
1.为了方便测试和进行快速开发,可以编译成可执行文件。不用打包成apk就可以复制到Android设备上直接执行
#独立可执行模块的Andriod.mk文件
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := module
LOCAL_SRC_FILES := module.c
LOCAL_STAITC_LIBRAYIES := AVI
include $(BUILD_EXECUTABLE)
9.注意事项
1.假如我们本地库libhello-jni.so依赖于libTest.so(可以使用NDK下的ndk-depends查看so的依赖关系)
2.在Android 6.0版本之前,需要在加载本地库前先加载被依赖的so
3.在Android6.0版本之后,不能再使用预编译的动态库(静态库没问题)
# Android 6.0版本之前:
System.loadLibrary("Test");
System.loadLibrary("hello-jni");
# Android 6.0版本之后:
System.loadLibrary("hello-jni");
实例:
step1: 在src/main目录下新建ndk目录
step2:编写hello-jni.c和Android.mk
hellojni.c
#include<jni.h>
int test() {
return 123;
}
jint Java_com_lcj_ndktest_MainActivity_nativeTest() {
return test();
}
Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := hello-jni
LOCAL_SRC_FILES := hello-jni.c
include $(BUILD_SHARED_LIBRARY)
step3: 定义native方法
public class MainActivity extends AppCompatActivity {
// 加载so
{
System.loadLibrary("hello-jni");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView textView = findViewById(R.id.tv_text);
textView.setText(nativeTest() + "");
}
// 定义native
native int nativeTest();
}
step4: 配置app下的build.gradle
defaultConfig {
applicationId "com.lcj.ndktest"
minSdkVersion 19
targetSdkVersion 30
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
// 指定源文件的编译方式以及配置编译选项
externalNativeBuild {
ndkBuild {
abiFilters "arm64-v8a","armeabi-v7a"
}
}
}
// 配置编译脚本路径
externalNativeBuild {
ndkBuild {
path "src/main/ndk/Android.mk"
}
}