Android studio如何利用Android.mk编译生成多个so文件

来源:互联网 发布:玻璃排班优化软件 编辑:程序博客网 时间:2024/06/07 04:43

我们这次不用gradle 去生成SO文件,改用Android.mk 去编译。

一共分为2步:

1.在Java中编写要调用的静态方法和需要加载的库,并生成头文件。

2.配置gradle

3.配置Android.mk文件和application.mk文件

下面一步步的走:

首先需要在Java类中声明要调用的方法,以及要加载的库,我们在包下新建一个jniUtil类,如下所示

public class jniUtil {//要加载的库,生成的库格式为:lib+库名.so static{ System.loadLibrary("hello-jni"); }//要调用的本地方法,在c文件中该方法名称格式为:java_包名_类名_方法名 public static native String stringFromJNI();}


注意:在编译时该类中不能有汉字,包括注释,否则会出现编码GBK的不可映射字符错误。
接下来就是利用external Tools生成头文件.h,这里可参考点击打开链接
然后就会在main目录下生成Jni文件夹,并且包含.h文件。下面就是编写C文件,或者可以拷贝已经写好的C文件放置在该jni文件夹中.

2.配置gradle
我们这里不用gradle 去编译,而是只让他去加载已经生成的so库,改用android.mk 去编译(稍后配置android.mk)
在app的build.gradle 下的android 标签下添加:

sourceSets {        main {            jni.srcDirs = []//禁止gradle 自动编译,使用已经编译好的So库            jniLibs.srcDirs = ['src/main/jniLibs','libs']//指向要使用的库文件//的路径,前边的是自己项目的,后边的是第三方的so        }    }

从上面可以看出,我们生成的库是放在
src/main/jniLibs
目录下面的,那么这个是如何配置呢?还是在该gradle下面配置ndk的编译脚本,注意放在android标签外面:

tasks.withType(JavaCompile) {    compileTask -> compileTask.dependsOn CopyToJniLibs}task ndkBuild(type: Exec, description: 'Compile JNI source via NDK') {    Properties properties = new Properties()    properties.load(project.rootProject.file('local.properties').newDataInputStream())    def ndkDir = properties.getProperty('ndk.dir')    commandLine "$ndkDir/ndk-build.cmd", "NDK_PROJECT_PATH=$projectDir.absolutePath\\build", "APP_BUILD_SCRIPT=$projectDir.absolutePath\\src\\main\\jni\\Android.mk", "NDK_APPLICATION_MK=$projectDir.absolutePath\\src\\main\\jni\\Application.mk"    //你自己的mk文件目录}

在ndkbuild完成后把生成的so文件复制到jniLibs,这里和上面配置的加载so文件路径要一致哦

task CopyToJniLibs(type: Copy, dependsOn: 'ndkBuild', description: 'copy the native libs to jniLibs') {    from fileTree(dir: file(buildDir.absolutePath + '/libs'), include: '**/*.so')    into file('src/main/jniLibs')}

新建Android.mk和application.mk,这里我把Android.mk和application.mk放在jni文件夹下了,具体可以自己修改。默认生成的SO文件会在build下面的libs中,我们拷贝出来放到src/main/jniLibs下面。

3.配置Android.mk和Application.mk
先说Application.mk,APP_ABI := all代表生成所有平台的库文件。
也可以修改为APP_ABI := armeabi armeabi-v7a x86,代表生成这三个平台的so文件。
重点说下Android.mk.先看代码:

LOCAL_PATH := $(call my-dir) LOCAL_LDLIBS := -llog  LOCAL_CPP_FLAGS := -fno-rtti #声明一个预编译库的模块:共享库include $(CLEAR_VARS)   LOCAL_MODULE := jniUtilLOCAL_MODULE_FILENAME:=libjniUtilLOCAL_SRC_FILES :=jniUtil.c util.cinclude $(BUILD_SHARED_LIBRARY) 


解释一下各参数:
1.LOCAL_PATH := $(call my-dir)   指向当前目录的地址,包含该.mk

2.LOCAL_LDLIBS := -llog    

链接的库不产生依赖关系,一般用于不需要重新编译的库,如库不存在,则会报错找不到。且貌似只能链接那些存在于系统目录下本模块需要连接的库。如果某一个库既有动态库又有静态库,那么在默认情况下是链接的动态库而非静态库。
如:LOCAL_LDLIBS += -lm –lz –lc -lcutils –lutils –llog …
如果你的Android.mk文件中只有这么一行,那么将会采用动态链接。


3.LOCAL_CPP_FLAGS := -fno-rtti    缺省情况下都是用-fno-rtti来编译C++代码

4.include $(CLEAR_VARS)   清理掉所有以LOCAL_开头的内容,这句话是必须的,因为如果所有的变量都是全局的,所有的可控的编译文件都需要在一个单独的GNU中被解析并执行。

5.LOCAL_MODULE :=hello-jni,
调用的库名,用来区分android.mk中的每一个模块。文件名必须是唯一的,不能有空格。注意,这里编译器会为你自动加上一些前缀lib和后缀.so,来保证文件是一致的。

6.LOCAL_SRC_FILES :=jniUtil.c util.c
变量必须包含一个C、C++或者java源文件的列表,这些会被编译并聚合到一个模块中,文件之间可以用空格或Tab键进行分割,换行请用"\"

7.include $(BUILD_SHARED_LIBRARY)  来生成一个动态库libhello-jni.so

如果要生成多个库文件,则在下面可以再加入

include $(CLEAR_VARS)LOCAL_MODULE := UtilLOCAL_MODULE_FILENAME:=libUtilLOCAL_SRC_FILES := util.cinclude $(BUILD_SHARED_LIBRARY)
 那么则可以生成libUtil.so文件

8.rebuild 一下,可以查看src/main/jniLibs目录下生成了so文件.至此编译完成.

后话:
要记得在gradle.properties文件中加入

android.useDeprecatedNdk=true
否则会报错!


                                             
0 0
原创粉丝点击