熟悉开发JNI基本流程以后,我来尝试写一下传递多种数据类型的情况。包括int、String、int[ ] 类型。这次我把这些native方法放在一个类中。
定义本地接口方法:
package com.example.manzuo.jni;
public class JNIUtils {
static {
System.loadLibrary("Message");
}
public native String callC();
//给C代码传递 多个参数
public native int javaCallCSendInts(int i,int j);
// 给C代码传递字符 数据
//应用场景:把web 请求的url用jni返回,防止别人反编译后拿到url
public native String javaCallCSendString(String params);
//给C代码传递 整形数组
//应用场景:图像,音频处理。
public native int[] javaCallCSendIntArray(int[] arraydata);
private JNIUtils(){}
public static JNIUtils instance = new JNIUtils();
public static JNIUtils getInstance(){
return instance;
}
}
然后 编写对应的C代码的实现
#include <stdio.h>
#include <jni.h>
#include <string.h>
char* Jstring2CStr(JNIEnv* env, jstring jstr)
{
char* rtn = NULL;
jclass clsstring = (*env)->FindClass(env,"java/lang/String");
jstring strencode = (*env)->NewStringUTF(env,"GB2312");
jmethodID mid = (*env)->GetMethodID(env,clsstring, "getBytes", "(Ljava/lang/String;)[B");
jbyteArray barr= (jbyteArray)(*env)->CallObjectMethod(env,jstr,mid,strencode); // String .getByte("GB2312");
jsize alen = (*env)->GetArrayLength(env,barr);
jbyte* ba = (*env)->GetByteArrayElements(env,barr,JNI_FALSE);
if(alen > 0)
{
rtn = (char*)malloc(alen+1); //"\0"
memcpy(rtn,ba,alen);
rtn[alen]=0;
}
(*env)->ReleaseByteArrayElements(env,barr,ba,0); //
return rtn;
}
jstring Java_com_example_manzuo_jni_JNIUtils_callC(JNIEnv* env,jobject obj){
// return **env.NewStringUTF(env,"message from C returned");
return (*env)->NewStringUTF(env,"message from C returned");
}
//传递多个参数的情况:这个方法用来 计算两个数的和。
jint Java_com_example_manzuo_jni_JNIUtils_javaCallCSendInts(JNIEnv * env, jobject object, jint x, jint y){
// 由jni.h文件中定义得知:java中的int就是c语言中的int。
return x+y;
}
//传递String 类型的情况:返回一个新的字符串“你好 xxx”.
//这里的str 是java中的String, 在C语言中不能直接操作str(java总的String)。怎么做呢?
// 把java语言中的字符串转换成C 语言中的 char数组,下面的Jstring2CStr方法 就是做这个工作。
jstring Java_com_example_manzuo_jni_JNIUtils_javaCallCSendString(JNIEnv * env, jobject object, jstring str){
char* c = Jstring2CStr(env,str);
char* hi = "Hi 你好 ";
// 这个C语言中的函数 就是字符串拼接函数,注意对字符串需要引入string.h 头文件
// 函数执行过后,第一个参数的值就已经被操作了,这里是c 变量,那么c的值就变了。
strcat(c,hi);
return (*env)->NewStringUTF(env,c);
}
//传递int[] 数组类型的情况: 对数组中的每个数字*2 。 在C语言中要处理java数组,(注意是java数组不是C的数组)需要知道 数组长度和 如何遍历数组。
//在jni.h头文件 中我找到了 如下定义
// 得到java数组长度
// jsize (*GetArrayLength)(JNIEnv*, jarray);
// 得到java传递过来的int数组,第三个参数表示是否对数组中的元素拷贝,传0、1都行。
// jint* (*GetIntArrayElements)(JNIEnv*, jintArray, jboolean*); 遍历java数组元素
//注意:不能一上来直接用C语言操作,必须 转化为C语言的东西。再进行操作.
jintArray Java_com_example_manzuo_jni_JNIUtils_javaCallCSendIntArray(JNIEnv * env, jobject object, jintArray jarray){
int length = (*env)->GetArrayLength(env,jarray);
//由于jint和int是一样的。所以用int* 接收.
int* array = (*env)->GetIntArrayElements(env,jarray,0);
int i=0;
for(;i<length;i++){
array[i] = array[i] * array[i];
}
return jarray;
}
注:在碰到要传递的其他类型时,也可以用这几种类型来实现,比如传递char ,那么就可以用String来表示,要传递String [ ] ,可以考虑将数组中的数据转为一个
大的字符串,然后用String。总之简单就行。
-----------------------------------------------Android.mk----------------------------------------
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := Message
LOCAL_SRC_FILES := Message.c
include $(BUILD_SHARED_LIBRARY)
执行结果:以上调试均执行成功。