Android studio 2.0集成NDK

前言

现在的ndk开发已经越来越便捷,打开老电脑的AS2.0,再一次对ndk-build的编译方式有了新的认识,以前对jni、libs、jniLibs这些目录理解有点凌乱。

开发环境:

  • windows 7
  • android-ndk-r14b
  • android studio 2.0

步骤

一.local.properties添加ndk路径
ndk.dir=D\:\\download\\android-ndk-r14b  

未添加则会报出下面的提示

二.gradle.properties文件,添加
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.

三.创建jni目录

新目录 src/main/jni

四.ndk-build编译
  • 自动编译 (不需要手动执行ndk-build命令)
  • 手动编译 (需要手动执行ndk-build命令)

自动编译

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 -C app\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相对容易点了