今天刚整了一下JNI,在百度上看了好多博客,好像在遇到问题方面解释的都比较少,安卓应用程序使用ndk开发的时候就使用了JNI,而且cocos2d-x移植到安卓平台的时候也有JNI的使用。
废话不多说,贴代码,对了,这个例子是在别的博客上看到了,但是他没有解释错误的方面
public class Sample1 {
public native int intMethod(int n);
public native boolean booleanMethod(boolean bool);//因为这个都是没有实现的,所以加上native,感觉跟c++里面方法的声名类似
public native String stringMethod(String text);
public native int intArrayMethod(int[] intArray);
public static void main(String[] args) {
System.loadLibrary("Sample1");//这个函数用来加载在windows平台的Sample1.dll,就是接下来就说的生成的动态链接库
Sample1 sample = new Sample1();
int square = sample.intMethod(5);
boolean bool = sample.booleanMethod(true);
String text = sample.stringMethod("Java");
int sum = sample.intArrayMethod(new int[]{1,2,3,4,5,8,13});
System.out.println("intMethod: " + square);
System.out.println("booleanMethod: " + bool);
System.out.println("stringMethod: " + text);
System.out.println("intArrayMethod: " + sum);
}
}
然后javac得到.class文件,接着用javah -classpath . Sample1得到Sample1.h头文件 -classpath 是指定文件所在目录,一个点就代表当前目录,贴出Sample1.h
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class Sample1 */
#ifndef _Included_Sample1
#define _Included_Sample1
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: Sample1
* Method: intMethod
* Signature: (I)I
*/
JNIEXPORT jint JNICALL Java_Sample1_intMethod
(JNIEnv *, jobject, jint);
/*
* Class: Sample1
* Method: booleanMethod
* Signature: (Z)Z
*/
JNIEXPORT jboolean JNICALL Java_Sample1_booleanMethod
(JNIEnv *, jobject, jboolean);
/*
* Class: Sample1
* Method: stringMethod
* Signature: (Ljava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_Sample1_stringMethod
(JNIEnv *, jobject, jstring);
/*
* Class: Sample1
* Method: intArrayMethod
* Signature: ([I)I
*/
JNIEXPORT jint JNICALL Java_Sample1_intArrayMethod
(JNIEnv *, jobject, jintArray);
#ifdef __cplusplus
}
#endif
#endif
然后贴出实现的代码
#include "Sample1.h"
#include <string>
#include <string.h>
#include <algorithm>
JNIEXPORT jint JNICALL Java_Sample1_intMethod
(JNIEnv *env, jobject obj, jint num)
{
return num * num;
}
JNIEXPORT jboolean JNICALL Java_Sample1_booleanMethod
(JNIEnv *env, jobject obj, jboolean boolean)
{
return !boolean;
}
JNIEXPORT jstring JNICALL Java_Sample1_stringMethod
(JNIEnv *env, jobject obj, jstring string)
{
const char* str = env->GetStringUTFChars(string, 0);
char cap[128];
strcpy_s(cap, str);
env->ReleaseStringUTFChars(string, 0);
std::string strs(cap);
std::transform(strs.begin(), strs.end(), strs.begin(), toupper);
return env->NewStringUTF(strs.c_str());
}
JNIEXPORT jint JNICALL Java_Sample1_intArrayMethod
(JNIEnv *env, jobject obj, jintArray array)
{
int i, sum = 0;
jsize len = env->GetArrayLength(array);
jint *body = env->GetIntArrayElements(array, 0);
for (i = 0; i < len; ++i)
{
sum += body[i];
}
env->ReleaseIntArrayElements(array, body, 0);
return sum;
}
这里的env使用的方法是固定的,JNIEnv提供了很多在java和c++之间数据转换的方法
这里我使用vs2013生成动态链接库,生成动态链接库的时候要注意,如果使用的是64位的机子,那可能会报Can't load IA 32-bit .dll on a AMD 64-bit platform这个错误,原因就是字面上的意思,怎么生成64位的库呢
生成-->配置管理器-->活动平台解决方案。把从此处复制选择为x64,然后把平台选择为x64,然后重新生成就可以生成64位的动态链接库了
还有一个比较坑爹的错误找不到或无法加载主类 Sample1,这个出现的原因好像是classpath最后少了一个分号,也许你认为你的classpath是正确的,但是真的就是缺少了最后面一个分号;
最后成功了之后就会正常输出了