5

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

 3 years ago
source link: http://www.androidchina.net/4806.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
AndroidStudio2.0搭建Ndk环境&成功编译使用 – Android开发中文站
你的位置:Android开发中文站 > Android开发 > 新手入门 > 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文件)
20160423135138866
然后最关键的是要在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个文件,当然下面的那个文件不用管它了
20160423135736711
然后把生成的这俩文件放到刚才创建的jni里面
下面就是编写cpp文件Android.mk Application.mk文件了
20160423135832697
.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目录下
20160423140008809
然后是在我们的代码中使用它

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

转载请注明:Android开发中文站 » AndroidStudio2.0搭建Ndk环境&成功编译使用


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK