AndroidStudio2.0搭建Ndk环境&成功编译使用

现在使用Ndk开发的场景还蛮多,游戏引擎、音视频开发等都能涉及到,以前的工程大部分都是Eclipse的工程目录,但是App开发现在大部分都是在AndroidStudio开发工具中进行的,那就有个问题了?怎么在As中搭建Ndk的环境呢。这就是本篇文章所要解答的,并且会创建一个小例子,编译成.so文件,且在项目中使用。Come on….

在没具体动手之前我们想一想怎么实现比较好吧,假如我们新建一个As2.0的工程,然后按照他的目录结构把jni层文件放到指定的目录下,然后进行开发,固然可行,可行是可行,但是代价就是Sdk开发和Ndk开发就分离了,不在一个工程目录下,不符合我们的预期,那就换种思路吧。庆幸的是,As的gradle脚本功能比较强大,可以指定源码文件,操作任务等。如果只是修改一下配置文件,就把事情给做好了,那岂不是皆大欢喜。好吧 开始做了。

首先在工程Module的src目录下新建一个jni目录(存放我们的c、c++源码及mk文件)
AndroidStudio2.0搭建Ndk环境&成功编译使用_第1张图片
然后最关键的是要在build.gradle配置一下说明jni里面的代码是咱们的ndk编译代码位置,及做一些编译任务的处理 下面配置代码由 成都 小妖 提供,特别感谢他

task buildNative(type: Exec, description: 'Compile JNI source via NDK') {
    def ndkDir = android.ndkDirectory

    if (Os.isFamily(Os.FAMILY_WINDOWS)) {
        commandLine "$ndkDir/ndk-build.cmd",
                '-C', file('src/jni').absolutePath, // Change src/main/jni the relative path to your jni source
                '-j', Runtime.runtime.availableProcessors(),
                'all',
                'NDK_DEBUG=1'
    } else {
        commandLine "$ndkDir/ndk-build",
                '-C', file('src/jni').absolutePath, // Change src/main/jni the relative path to your jni source
                '-j', Runtime.runtime.availableProcessors(),
                'all',
                'NDK_DEBUG=1'
    }
}
//在 mac 中 commandLine "$ndkDir/ndk-build", 但是在windows中 commandLine "$ndkDir/ndk-build.cmd",额,坑
//
task cleanNative(type: Exec, description: 'Clean JNI object files') {
    def ndkDir = android.ndkDirectory
    if (Os.isFamily(Os.FAMILY_WINDOWS)) {
        commandLine "$ndkDir/ndk-build.cmd",
                '-C', file('src/jni').absolutePath, // Change src/main/jni the relative path to your jni source
                'clean'
    } else {
        commandLine "$ndkDir/ndk-build.cmd",
                '-C', file('src/jni').absolutePath, // Change src/main/jni the relative path to your jni source
                'clean'
    }
}
//
clean.dependsOn 'cleanNative'

tasks.withType(JavaCompile) {
    compileTask -> compileTask.dependsOn buildNative
}

注意上面的有一个变化的地方就是jni的路径在哪,src/jni 如果跟我不一样的,应该写你的具体位置

然后在我们的代码中添加一个Native方法,就让他打印一个helloworld吧

public native void printHelloworld();

然后使用javah命令 生成对应的.h头文件

这样会在下面目录生成2个文件,当然下面的那个文件不用管它了
AndroidStudio2.0搭建Ndk环境&成功编译使用_第2张图片
然后把生成的这俩文件放到刚才创建的jni里面
下面就是编写cpp文件Android.mk Application.mk文件了

.h文件代码

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_qbao_ticket_MainActivity */

#ifndef _Included_com_qbao_ticket_MainActivity
#define _Included_com_qbao_ticket_MainActivity
#ifdef __cplusplus
extern "C" {
#endif
/* * Class: com_qbao_ticket_MainActivity * Method: add * Signature: ()V */
JNIEXPORT void JNICALL Java_com_qbao_ticket_MainActivity_printHelloworld
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

.cpp文件代码

#include <jni.h>
#include <android/log.h>
#include "com_qbao_ticket_MainActivity.h"
#define LOG_TAG "System.out.c"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)

JNIEXPORT void JNICALL Java_com_qbao_ticket_MainActivity_printHelloworld
  (JNIEnv *, jobject){
  LOGI("hello world! come from jni");
}

注意新建写的时候 一定要加上

#include "com_qbao_ticket_MainActivity.h"

然后写咱们的mk文件,先来Android.mk

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := lalala

LOCAL_SRC_FILES := com_qbao_ticket_MainActivity.cpp

LOCAL_LDLIBS += -llog

include $(BUILD_SHARED_LIBRARY)

要改的地方是咱们的module名称源文件列表 这里根据自己的代码设置就好了

接下来Application.mk

APP_ABI := all
APP_PLATFORM := android-8

设置了全平台,当然不设置也可以 默认就行了

点击这个按钮 开始编译

编译成功会在src目录下生成一个libs和obj.local目录
然后就生成了咱们命名的liblalala.so文件 格式为lib{模块名}.so

下面是怎么在代码中使用咱们生成的.so文件了

把我们的编译生成好的.so文件拷贝到代码的libs中armeabi目录下
AndroidStudio2.0搭建Ndk环境&成功编译使用_第3张图片
然后是在我们的代码中使用它

static {
   System.loadLibrary("lalala");
}
public native  void printHelloworld();

注意load的时候写模块名 不是文件名 这里是lalala 然后在MainActivity里面调用这个printHelloworld方法
打印一下log

好了到这里在As2.0中搭建Ndk环境并且编译so文件,并使用so文件的介绍已经讲完了,后面会在这个基础上编译一些音视频模块的代码,然后封装使用。期待吧。。。

build.gradle全部配置查看

import org.apache.tools.ant.taskdefs.condition.Os

apply plugin: 'com.android.application'

dependencies {
    compile fileTree(dir: 'libs', include: '*.jar')
}

android {
    compileSdkVersion 21
    buildToolsVersion "22.0.1"
    sourceSets {
        main {
            manifest.srcFile 'AndroidManifest.xml'
            java.srcDirs = ['src']
            resources.srcDirs = ['src']
            aidl.srcDirs = ['src']
            renderscript.srcDirs = ['src']
            res.srcDirs = ['res']
            assets.srcDirs = ['assets']
            jniLibs.srcDirs = ['libs']
        }

        // Move the tests to tests/java, tests/res, etc...
        instrumentTest.setRoot('tests')

        // Move the build types to build-types/<type>
        // For instance, build-types/debug/java, build-types/debug/AndroidManifest.xml, ...
        // This moves them out of them default location under src/<type>/... which would
        // conflict with src/ being used by the main source set.
        // Adding new build types or product flavors should be accompanied
        // by a similar customization.
        debug.setRoot('build-types/debug')
        release.setRoot('build-types/release')
    }
    buildTypes {
        debug {
            //proguardFile '/Users/xuchuang/Desktop/Stifler/WorkSpace/QBaoTicket_2.0/qbaoticket_2.0/proguard-project.txt'
            //signingConfig signingConfigs.qbaoticket
        }
        release {
            //signingConfig signingConfigs.qbaoticket
            //minifyEnabled true
            //proguardFile '/Users/xuchuang/Desktop/Stifler/WorkSpace/QBaoTicket_2.0/qbaoticket_2.0/proguard-project.txt'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_7
        targetCompatibility JavaVersion.VERSION_1_7
    }
    dexOptions {
        jumboMode true
    }
}

task buildNative(type: Exec, description: 'Compile JNI source via NDK') {
    def ndkDir = android.ndkDirectory

    if (Os.isFamily(Os.FAMILY_WINDOWS)) {
        commandLine "$ndkDir/ndk-build.cmd",
                '-C', file('src/jni').absolutePath, // Change src/main/jni the relative path to your jni source
                '-j', Runtime.runtime.availableProcessors(),
                'all',
                'NDK_DEBUG=1'
    } else {
        commandLine "$ndkDir/ndk-build",
                '-C', file('src/jni').absolutePath, // Change src/main/jni the relative path to your jni source
                '-j', Runtime.runtime.availableProcessors(),
                'all',
                'NDK_DEBUG=1'
    }
}
//在 mac 中 commandLine "$ndkDir/ndk-build", 但是在windows中 commandLine "$ndkDir/ndk-build.cmd",额,坑
//
task cleanNative(type: Exec, description: 'Clean JNI object files') {
    def ndkDir = android.ndkDirectory
    if (Os.isFamily(Os.FAMILY_WINDOWS)) {
        commandLine "$ndkDir/ndk-build.cmd",
                '-C', file('src/jni').absolutePath, // Change src/main/jni the relative path to your jni source
                'clean'
    } else {
        commandLine "$ndkDir/ndk-build.cmd",
                '-C', file('src/jni').absolutePath, // Change src/main/jni the relative path to your jni source
                'clean'
    }
}
//
clean.dependsOn 'cleanNative'

tasks.withType(JavaCompile) {
    compileTask -> compileTask.dependsOn buildNative
}

参考资料
http://blog.csdn.net/allen315410/article/details/41805719

支持原创 from 爆发的妞 qq 928320442

你可能感兴趣的:(android)