android jni环境搭建,Android NDK开发环境的配置(包括Eclipse和Gradle)

最近因为一个项目要在Android上使用OpenCV,所以补了一下Android NDK开发的知识,网上关于在Eclipse里进行NDK开发的文档比较多,但是很难找到在Android Studio或者IntelliJ里使用Gradle进行NDK开发的教程,这篇文章将会对两种情况都进行介绍。

这里我只是记录了一下基本的配置过程,并举了一个简单的小例子,并没有对其中的一些细节和原理进行介绍,毕竟我也是刚刚接触NDK。如果以后对NDK开发更加深入了解,我会再次进行补充。

基本环境配置

2、在Eclipse中安装Android Native Development Tools

在install new software中使用 Android Development Tools - https://dl-ssl.google.com/android/eclipse/,进行下载安装Android Native Development Tools。如下图:

619be42aa7c063f6c2763edebe2bdb53.png

3、设置NDK根目录:

Eclipse -> Window -> Preferences -> Android -> NDK,设置为NDK根目录。

7e9720955f5179b7d57b6a41dc4ed2bc.png

代码编写

4、创建接口类:

首先新建JNI的接口类, 包含使用的静态方法。 位置: 项目->src->[package]->JniClient.java

public class JniClient {

static public native String sayName();

}

5、编译接口类:

进入项目文件夹, 生成JNI的头文件, 使用如下cmd命令:

javah -classpath bin/classes -d jni com.hellomyjni.JniClient

命令解析:

javah 生成头文件;

-classpath 使用类的位置(bin/classes), 都是.class文件;

-d jni 指定生成文件的存储位置,这里是在jni文件夹下;

[classname] 需要生成JNI的类(com.example.hellomyjni.JniClient), 包括[package]。

6、生成头文件:

按F5刷新项目, 项目会自动生成jni文件夹, 并包含一个头文件 “com_example_hellomyjni_JniClient.h”。文件内容如下:

/* DO NOT EDIT THIS FILE - it is machine generated */

#include

/* Header for class com_example_hellomyjni_JniClient */

#ifndef _Included_com_example_hellomyjni_JniClient

#define _Included_com_example_hellomyjni_JniClient

#ifdef __cplusplus

extern "C" {

#endif

/*

* Class: com_example_hellomyjni_JniClient

* Method: sayName

* Signature: ()Ljava/lang/String;

*/

JNIEXPORT jstring JNICALL Java_com_example_hellomyjni_JniClient_sayName

(JNIEnv *, jclass);

#ifdef __cplusplus

}

#endif

#endif

注意:

此时头文件可能会报错,主要是JNICALL这类符号不能被解析(type JNICALL can’t be resolved)

解决方案:

Project Properties -> C/C++ General -> Path and Symbols

选择include标签,Add -> $Android_NDK_HOME/platforms/android-19/arch-arm/usr/include

(其中”android-19”替换为当前使用的android api版本)

选中All languages,最后Apply -> OK。

e96bdddf792202c13e5dc9a072873be4.png

7e0ee0c3346107c8081b70c19d5a5ba0.png

7、给Android项目添加NativeSupport:

右键点击项目在Android Tools里面点击”Add NativeSupport”, 就会在jni文件夹下自动生成: HelloMyJni.cpp和Android.mk.

这一步可能会报错:

Unable to launch cygpath. Is Cygwin on the path?] java.io.IOException: Cannot run program “cygpath”: CreateProcess error=2, The system cannot find the file specified

解决方法:

A、右键点击项目->Properties->C/C++ Build, 修改Build Command为 “${NDK_ROOT}/ndk-build.cmd”,其中NDK_ROOT为NDK根目录。

B、右键点击项目->Properties->C/C++ Build ->Environment, 添加变量名为NDK_ROOT的环境变量。

ndk-setup-build-command.png

8、修改生成的代码:

Android.mk不需要修改:LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := HelloMyJni

LOCAL_SRC_FILES := HelloMyJni.cpp

include $(BUILD_SHARED_LIBRARY)

HelloMyJni.cpp需要修改,添加头文件并编写实现函数。

A、添加头文件, 即JNI生成的头文件:

#include "com_example_hellomyjni_JniClient.h";

此时头文件的报错消失.

B、复制JNIEXPORT函数, 并填写参数名称。 完成函数编写,可以调用其他C++程序。

#include

#include "com_example_hellomyjni_JniClient.h"

JNIEXPORT jstring JNICALL Java_com_example_hellomyjni_JniClient_sayName

(JNIEnv *env, jclass) {

return env->NewStringUTF("I'm Spike!");

}

9、 调用JniClient:

在需要调用JniClient的类中添加:

static {

System.loadLibrary("HelloMyJni");

}

需要调用时使用如下代码就可以了:

JniClient.sayName();

调试

10、 jni代码调试:

最后、我们来看一下怎样来调试我们的NDK C/C++代码,打开jni/HelloMyJni.cpp文件,找地方打上断点,debug android Native Application,截图如下:

4c016806e27f41f1f59bba808110569a.png

发现没有Debug起来,控制台的错误如下:[2015-01-28 21:06:01 - HelloJni] Unknown Application ABI:

[2015-01-28 21:06:01 - HelloJni] Android

[2015-01-28 21:06:01 - HelloJni] Unknown Application ABI:

[2015-01-28 21:06:01 - HelloJni] NDK:

[2015-01-28 21:06:01 - HelloJni] Unknown Application ABI:

[2015-01-28 21:06:01 - HelloJni] WARNING:

[2015-01-28 21:06:01 - HelloJni] Unknown Application ABI:

[2015-01-28 21:06:01 - HelloJni] APP_PLATFORM

[2015-01-28 21:06:01 - HelloJni] Unknown Application ABI:

[2015-01-28 21:06:01 - HelloJni] android-9

[2015-01-28 21:06:01 - HelloJni] Unknown Application ABI:

[2015-01-28 21:06:01 - HelloJni] is

[2015-01-28 21:06:01 - HelloJni] Unknown Application ABI:

[2015-01-28 21:06:01 - HelloJni] larger

[2015-01-28 21:06:01 - HelloJni] Unknown Application ABI:

[2015-01-28 21:06:01 - HelloJni] than

[2015-01-28 21:06:01 - HelloJni] Unknown Application ABI:

[2015-01-28 21:06:01 - HelloJni] android:minSdkVersion

[2015-01-28 21:06:01 - HelloJni] Unknown Application ABI:

[2015-01-28 21:06:01 - HelloJni] 3

[2015-01-28 21:06:01 - HelloJni] Unknown Application ABI:

[2015-01-28 21:06:01 - HelloJni] in

[2015-01-28 21:06:01 - HelloJni] Unknown Application ABI:

[2015-01-28 21:06:01 - HelloJni] ./AndroidManifest.xml

[2015-01-28 21:06:01 - HelloJni] Unknown Application ABI:

[2015-01-28 21:06:01 - HelloJni]

[2015-01-28 21:06:01 - HelloJni] Unknown Application ABI:

[2015-01-28 21:06:01 - HelloJni]

[2015-01-28 21:06:01 - HelloJni] Unknown Application ABI:

[2015-01-28 21:06:01 - HelloJni]

[2015-01-28 21:06:01 - HelloJni] Unknown Application ABI:

[2015-01-28 21:06:01 - HelloJni]

all

[2015-01-28 21:06:01 - HelloJni] Unable to detect application ABI's

这是由于android:minSdkVersion和项目的编译版本不一致,造成的,我们改成一致,在Application.mk文件中加入APP_PLATFORM := android-8 // android-8和android:minSdkVersion一致

再次运行,发现又报了一个错误:[2015-01-28 21:13:32 - HelloJni] gdbserver output:

[2015-01-28 21:13:32 - HelloJni] run-as: exec failed for lib/gdbserver Error:No such file or directory

[2015-01-28 21:13:32 - HelloJni] Verify if the application was built with NDK_DEBUG=1

这个需要我们再次修改一下C/C++ Build command:Properties–>C/C++ Build,在build command中输入:${NDK_ROOT}/ndk-build.cmd NDK_DEBUG=1,主要是增加了NDK_DEBUG=1,截图如下:

ndk-setup-build-command.png

再次Debug我们的项目,发现没有进我们打的断点,但是我们发现了Android Native Application gdb运行起来了,如下:

1a00579b260a6c798f673307d2d3088b.png

但是控制台上打印出如上图的错误代码,这个错误信息对我们的影响不大,退出程序,再次进入,我们发现,进入断点了,可以调试了。

二、Gradle(IntelliJ/Android Studio)

基本构建

1、如上一节,创建接口类JniClient;

2、在src/main路径下创建jni文件夹;

3、使用External Tools代替手动编写javah命令生成头文件:

A、如下图找到External Tools,点击+添加javah工具;

5f2abc98f506cd34662098610cc56dcc.png

B、按下图进行javah工具的编辑;

993ebe63d218d02e9195ae463b1dd402.png

编辑完成,点击OK;

4、右击JniClient类,选择Android Tools -> javah,会自动在jni目录中生成com_example_hellomyjni_JniClient.h;

5、新建HelloMyJni.cpp文件,并添加和上一节相同的内容;

6、在build.gradle文件中配置ndk:

android {

defaultConfig {

...

ndk{

moduleName "hello"

}

}

}

7、在local.properties文件中配置ndk.dir:sdk.dir=D:\android\sdk

ndk.dir=D:\android\ndk

8、经过以上配置,就可以点击”Run”,在手机上看到效果了。

原理介绍

那么实际上发生了什么?

gradle默认将src/main/jni作为本地代码目录,当gradle构建app时,它会用一个自动生成的Android.mk(存在于app/build/intermediates/ndk/debug/Android.mk)自动运行ndk-build.cmd来编译本地代码,生成libs和obj文件夹,存放于app/build/intermediates/ndk/debug/路径。然后gradle会将libs文件夹打包到最终的apk中。

进阶

更近一步地,如果想和Eclipse中那样用自己写的Android.mk来控制编译,要怎么做呢?

1、在jni中新建Android.mk和Application.mk,并编写和Eclipse中开发相同的内容;

2、在build.gradle中添加以下代码:

android {

...

sourceSets.main.jni.srcDirs = []

task ndkBuild(type: Exec, description: 'Compile JNI source via NDK') {

def ndkDir = project.plugins.findPlugin('com.android.application').sdkHandler.getNdkFolder()

commandLine "$ndkDir/ndk-build.cmd",

'NDK_PROJECT_PATH=build/intermediates/ndk',

'NDK_LIBS_OUT=src/main/jniLibs',

'APP_BUILD_SCRIPT=src/main/jni/Android.mk',

'NDK_APPLICATION_MK=src/main/jni/Application.mk'

}

tasks.withType(JavaCompile) {

compileTask -> compileTask.dependsOn ndkBuild

}

}

A、sourceSets.main.jni.srcDirs = [] 这句话禁止gradle去默认编译本地代码;

B、’NDK_LIBS_OUT=src/main/jniLibs’, 这句话将生成的so文件输出到jniLibs中,而jniLibs是gradle默认的本地类库文件夹,将会打包到apk;

这样就大工告成了!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值