您的位置:首页 > 移动开发 > Android开发

【Android学习笔记】如何使用Eclipse在Android项目中调用C/C++代码,及遇到的错误解决方法

2013-11-07 11:35 567 查看
首先,我们创建一个工程,这里名叫“DemoJNI”,包名按照自己习惯改好,然后各种next最后finish。



为了条理清晰,我在主Activity之外创建了一个JniInterface类,专门作为JAVA和C/C++之间的接口。在这个类中,我们写几个native方法,就是要通过C/C++代码来实现的方法。完整的JniInterface类如下:

package com.startsi.demojni;

public class JniInterface {
public native int intMethod(int x,int y);
public native String stringMethod(String str);
public native byte byteMethod(byte b);
}


保存

注意!native方法不能在JAVA中添加实现,必须在C/C++代码中实现!

下面我们使用javah命令生成JNI头文件

点击Run->External Tools->External Tools Configuration,选中左侧的“Program”,点左上角的新建按钮,建立一条控制台指令。右边的name是你给这个指令起的代号,我们就叫javah;location是你的javah二进制文件的路径,一般就实在JAVA_HOME的bin目录下;working directory是你的java代码生成的.class文件的路径,你只需要设置到classes这一层就可以了,如图。

解释一下Arguments,这里的参数就相当于我们在终端输入的指令的参数。javah的参数中

-classpath [类文件的路径] ;-d [输出的头文件的位置] 。参考下图的例子设置好后Apply,然后RUN!



好的,我们成功地遇到了问题!这是什么鸟?



很不幸,我不知道问题出在哪,希望哪位明白的能告诉我解决办法。

不过这条路走不通,我们就绕路,也能走的过去。我直接打开linux的终端,进入上面Working directroy设置的那个路径,直接输入 javah com.startsi.demojni.JniInterface 注意参数一定要按照此格式输入完整的包名.类名。然后我们发现在当前目录下出现了一个新的头文件 。先不着急,再打开eclipse,在左侧工程列表栏中右击你的工程,选择Android Tools -> Add Native Support
直接Finish就可以了。然后刷新你的工程,发现多了一个JNI文件夹。现在把刚才生成的头文件拷贝到这个JNI文件夹中,然后刷新你的工程,看是否成功添加进来了。如下图示:



打开这个头文件,发现包含jni.h的一行报错 Unresolved inclusion: <jni.h>

解决方法:右击工程,-> properties 左侧选择 C/C++ General -> Paths and symbols

添加jni.h的路径,顺便把jni_md.h的路径也添加进来,不然待会声明函数的部分依然报错。如下图



C++的头文件之后要用到的话,路径位置也在这里添加上。

应用后重新编译,发现错误没有了,好,下一步。

打开jni中生成的cpp文件,把我们弄出来的头文件包含进去。然后把头文件中声明的函数挨个实现。先上代码吧。

//DemoJNI.cpp
#include <jni.h>
#include "com_startsi_demojni_JniInterface.h"

#include <string>

/*
* Class:     com_startsi_demojni_JniInterface
* Method:    intMethod
* Signature: (II)I
*/
JNIEXPORT jint JNICALL Java_com_startsi_demojni_JniInterface_intMethod
(JNIEnv *env, jobject obj, jint x, jint y){
return x*y;
}
/*
* Class:     com_startsi_demojni_JniInterface
* Method:    stringMethod
* Signature: (Ljava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_startsi_demojni_JniInterface_stringMethod
(JNIEnv *env, jobject obj, jstring str){
const char* ptr = env->GetStringUTFChars(str,0);
return env->NewStringUTF(ptr);
}
/*
* Class:     com_startsi_demojni_JniInterface
* Method:    byteMethod
* Signature: (B)B
*/
JNIEXPORT jbyte JNICALL Java_com_startsi_demojni_JniInterface_byteMethod
(JNIEnv *env, jobject obj, jbyte b){
char byte = (char)b;
byte += 1;
return (jbyte)byte;
}

在这里,JNI中C/C++与JAVA之间的参数传递不做重点,想要了解有关内容,请参阅

http://www.20864.com/201258/221.html

然后进入我们之前设置javah指令的地方,再新建一个ndk_build指令,location中设置到你的ndk-build所在的位置,working directory设置为工程下的jni目录。如图



注意路径最后是ndk-build,不是ndk-build.cmd。设置好后apply,之后Run。可以看到 .so的库文件已经生成了,你可以在工程的 libs/armeabi/ 目录下找到库文件。

对了,这里要说一下Android.mk文件的写法。这个脚本文件在你的jni目录下,ndk在编译生成库文件时会按照该文件的说明进行编译。某些工程还需要添加一个Application.mk的文件,和Android.mk共同作用。Android.mk的写法请参照/article/1948410.html

我们已经在JniInterface类中声明了几个本地方法,并且在C/C++代码中实现了这写本地方法,也编译生成了.so的库文件。下面我们只要在想要调用本地代码的时候调用JniInterface中的方法就可以了。

首先要在MainActivity中加载库

//Load Native Library
static
System.loadLibrary("DemoJNI");
}
然后给MainActivity添加一个TextView,这里我们直接使用HelloWorld那个Textview。不罗嗦了,直接看代码吧。

TextView rtv;
JniInterface jn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

rtv = (TextView)findViewById(R.id.returnTextView);
rtv.setText("intMethod return : " + jn.intMethod(5, 5) + "\n"
+ "stringMethod return : " + jn.stringMethod("success !") + "\n"
+ "byteMethod return : " + jn.byteMethod((byte)'a'));
}
然后运行一下程序,诶,出错了



痛苦啊!找了各种资料都没有有效的解决这个问题的办法。求解救啊!

之前明明可以成功的啊?这下连之前写好的工程都不能运行了,也是报这个错。求路过的大牛解救!!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: