今天剛整了一下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是正確的,但是真的就是缺少了最後面一個分號;
最後成功了之後就會正常輸出了