前言
现在的ndk开发已经越来越便捷,打开老电脑的AS2.0,再一次对ndk-build的编译方式有了新的认识,以前对jni、libs、jniLibs这些目录理解有点凌乱。
开发环境:
步骤
ndk.dir=D\:\\download\\android-ndk-r14b
未添加则会报出下面的提示
android.useDeprecatedNdk=true //低版本插件
未添加则会报出下面的提示
Error:(27, 1) A problem occurred evaluating project ‘:app’.
Error: NDK integration is deprecated in the current plugin. Consider trying the new experimental plugin. For details, see http://tools.android.com/tech-docs/new-build-system/gradle-experimental. Set “android.useDeprecatedNdk=true” in gradle.properties to continue using the current NDK integration.
新目录 src/main/jni
自动编译
android studio根据ndk option自动生成Android.mk文件
在build.gradle文件中
1.指定jni目录,jni.srcDirs 是源码的位置
sourceSets {
main {
println("---> jni默认目录 $jni")
jni.srcDirs = ['src/main/jni']
//编译 jni目录 根据defaultConfig的ndk配置自动生成mk文件 中间文件在app\build\intermediates\ndk
}
}
2.配置ndk option
defaultConfig {
ndk {
//lib的名称,对应Android.mk文件的LOCAL_MODULE
moduleName "JniTest"
//cpu的类型
abiFilters "armeabi", "armeabi-v7a", "x86", "mips", "arm64-v8a", "x86_64", "mips64"
}
}
运行程序,生成中间文件(app\build\intermediates\ndk),这种方式编译的的so链接库会自动打包到apk的app/libs目录
手动编译
手动书写Android.mk文件,使用ndk-build命令编译
1.在build.gradle文件中,禁止自动编译ndk
sourceSets {
main {
println("---> jni默认目录 $jni")//一旦 添加了 ndk 就会自动编译ndk 默认src/main/jni
jni.srcDirs = []//disable automatic ndk-build call 禁止自动编译 src/main/jni目录
println("---> jni新目录 $jni")
}
}
2.在jni目录下,添加Android.mk和Application.mk文件
Android.mk用于设置库文件的名称,源码路径,Application.mk文件配置编译版本
Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := test #库名称
LOCAL_LDFLAGS := -Wl,--build-id
LOCAL_SRC_FILES :=main.cpp
LOCAL_C_INCLUDES += /app/src/main/jni
LOCAL_C_INCLUDES += /app/src/debug/jni
include $(BUILD_SHARED_LIBRARY)
Application.mk
#APP_PLATFORM (minimum is android-21 for 64bit support) 需要ndk11及以上版本才能编译64位
#APP_ABI := armeabi armeabi-v7a mips x86 arm64-v8a x86_64 mips64
#APP_PLATFORM := android-21 #编译版本
APP_ABI := all #编译支持的abi 对应gradle的ndk option的abiFilters
3.在项目根目录下 执行命令 ndkroot/ndk−build−Capp\src\main\jni {ndk_root}是ndk路径,如ndk是D:\download\android-ndk-r14b,则命令为
D:\download\android-ndk-r14b\ndk-build -C app\src\main\jni
ndk-build输出的中间文件在app\src\main\libs
手动编译有利于了解GNU make的编译过程,但是需要注意将jniLibs的目录改为src/main/libs,so库才会被打包进apk中,原因是因为jniLibs.srcDir默认是src/main/jniLibs目录,然而这里并没有src/main/jniLibs目录,只有src/main/libs。。当然也可以创建src/main/jniLibs目录,拷贝so文件进去。否者运行程序将找不到so库
jniLibs.srcDirs = ["src/main/libs"]//依赖libs目录
半手动编译
对手动编译优化,使用gradle的task 执行ndk-build
在build.gradle文件中新建task
//自带mk文件 task自动编译
task buildNative(type: Exec) {
def ndkDir = android.ndkDirectory
println("---> ndk dir: ${ndkDir}")
println("---> jni file dir: ${file('src/main/jni').absolutePath}")
commandLine "$ndkDir/ndk-build.cmd",//等同于打开cmd 输入命令ndk-build.cmd -C src/main/jni
'-C', file('src/main/jni').absolutePath, // 根据jni的Android.mk生成so,在src/libs下
'-j', Runtime.runtime.availableProcessors(),//-j参数,并行执行构建命令
'all',
'NDK_DEBUG=1'
}
tasks.withType(JavaCompile) {
//项目编译的时候就执行buildNative任务
compileTask -> compileTask.dependsOn 'buildNative'
}
备注 ndk-build的常用命令
ndk-build 编译
ndk-build -C <project路径> 指定工程的目录
ndk-build clean 清掉二进制文件
ndk-build NDK_DEBUG=1 编译为可调试版的二进制文件
ndk-build NDK_DEBUG=0 编译为release版
ndk-build NDK_LOG=1 打印出内部的NDK日志信息(用于调试NDK自己)
ndk-build NDK_APP_APPLICATION_MK=<文件路径> 用这里指定的路径寻找Application.mk文件
现在的android studio早已经弃用这种自我折腾的方式了,才会有 android.useDeprecatedNdk=true这种奇葩配置。新的android studio集成ndk相对容易点了