今天说的代码是从java层调用c代码,然后再反调java代码的。这里在java用的是静态注册,也就是jni方法名是根据java的文件路径生成的,不是动态注册。
先看:java注册jni,以及调用jni函数:
package com.duicky; import android.app.Activity; import android.content.Context; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; /** * C 调用 Java 例子 * * @author luxiaofeng * */ public class MainActivity extends Activity { //也就是你mk配置文件中的 LOCAL_MODULE := NDK_03 private static final String libSoName = "NDK_04"; private static final String tag = "MainActivity"; public static Context mContext = null; private Button btnClickStatic = null; private Button btnClick = null; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); mContext = this; //初始化控件 initViews(); } /** * 初始化控件 */ private void initViews() { btnClick = (Button) this.findViewById(R.id.btn_click); btnClick.setOnClickListener(new OnClickListener() { public void onClick(View v) { sayHello(); } }); btnClickStatic = (Button) this.findViewById(R.id.btn_click_static); btnClickStatic.setOnClickListener(new OnClickListener() { public void onClick(View v) { getTime(); } }); } public native void getTime() ; public native void sayHello() ; /** * 载入JNI生成的so库文件 */ static { System.loadLibrary(libSoName); } }
然后我们再看JNI的mk函数:
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_C_INCLUDES := $(LOCAL_PATH)/include LOCAL_LDLIBS += -L$(SYSROOT)/usr/lib -llog LOCAL_MODULE := NDK_04 LOCAL_SRC_FILES := \ CToJava.c \ Provider.c include $(BUILD_SHARED_LIBRARY)是动态库,需要在libs加载libNDK_04.so动态库
jni函数,当java传下来,就带有了JNIEnv参量
#include <string.h> #include <android/log.h> #include <jni.h> #include "Provider.h" JNIEnv* jniEnv; /** * Java 中 声明的native getTime 方法的实现 */ void Java_com_duicky_MainActivity_getTime(JNIEnv* env, jobject thiz) { if(jniEnv == NULL) { jniEnv = env; } GetTime(); } /** * Java 中 声明的native sayHello 方法的实现 */ void Java_com_duicky_MainActivity_sayHello(JNIEnv* env, jobject thiz) { if (jniEnv == NULL) { jniEnv = env; } SayHello(); }
下面这个类是c中的方法,以及获取java类,和方法的初始化
#include "Provider.h" #include <android/log.h> extern JNIEnv* jniEnv; jclass TestProvider; jobject mTestProvider; jmethodID getTime; jmethodID sayHello; int GetProviderInstance(jclass obj_class); /** * 初始化 类、对象、方法 */ int InitProvider() { __android_log_print(ANDROID_LOG_INFO, "JNIMsg", "InitProvider Begin 1" ); if(jniEnv == NULL) { return 0; } if(TestProvider == NULL) { TestProvider = (*jniEnv)->FindClass(jniEnv,"com/duicky/TestProvider"); if(TestProvider == NULL){ return -1; } __android_log_print(ANDROID_LOG_INFO, "JNIMsg", "InitProvider Begin 2 ok" ); } if (mTestProvider == NULL) { if (GetProviderInstance(TestProvider) != 1) { (*jniEnv)->DeleteLocalRef(jniEnv, TestProvider); return -1; } __android_log_print(ANDROID_LOG_INFO, "JNIMsg", "InitProvider Begin 3 ok" ); } if (getTime == NULL) { getTime = (*jniEnv)->GetStaticMethodID(jniEnv, TestProvider, "getTime","()Ljava/lang/String;"); if (getTime == NULL) { (*jniEnv)->DeleteLocalRef(jniEnv, TestProvider); (*jniEnv)->DeleteLocalRef(jniEnv, mTestProvider); return -2; } __android_log_print(ANDROID_LOG_INFO, "JNIMsg", "InitProvider Begin 4 ok" ); } if (sayHello == NULL) { sayHello = (*jniEnv)->GetMethodID(jniEnv, TestProvider, "sayHello","(Ljava/lang/String;)V"); if (sayHello == NULL) { (*jniEnv)->DeleteLocalRef(jniEnv, TestProvider); (*jniEnv)->DeleteLocalRef(jniEnv, mTestProvider); (*jniEnv)->DeleteLocalRef(jniEnv, getTime); return -3; } __android_log_print(ANDROID_LOG_INFO, "JNIMsg", "InitProvider Begin 5 ok" ); } __android_log_print(ANDROID_LOG_INFO, "JNIMsg", "InitProvider Begin 6" ); return 1; } int GetProviderInstance(jclass obj_class) { if(obj_class == NULL) { return 0; } jmethodID construction_id = (*jniEnv)->GetMethodID(jniEnv, obj_class, "<init>", "()V"); if (construction_id == 0) { return -1; } mTestProvider = (*jniEnv)->NewObject(jniEnv, obj_class, construction_id); if (mTestProvider == NULL) { return -2; } return 1; } /** * 获取时间 ---- 调用 Java 方法 */ void GetTime() { if(TestProvider == NULL || getTime == NULL) { int result = InitProvider(); if (result != 1) { return; } } jstring jstr = NULL; char* cstr = NULL; __android_log_print(ANDROID_LOG_INFO, "JNIMsg", "GetTime Begin" ); jstr = (*jniEnv)->CallStaticObjectMethod(jniEnv, TestProvider, getTime); cstr = (char*) (*jniEnv)->GetStringUTFChars(jniEnv,jstr, 0); __android_log_print(ANDROID_LOG_INFO, "JNIMsg", "Success Get Time from Java , Value = %s",cstr ); __android_log_print(ANDROID_LOG_INFO, "JNIMsg", "GetTime End" ); (*jniEnv)->ReleaseStringUTFChars(jniEnv, jstr, cstr); (*jniEnv)->DeleteLocalRef(jniEnv, jstr); } /** * SayHello ---- 调用 Java 方法 */ void SayHello() { if(TestProvider == NULL || mTestProvider == NULL || sayHello == NULL) { int result = InitProvider() ; if(result != 1) { return; } } jstring jstrMSG = NULL; jstrMSG =(*jniEnv)->NewStringUTF(jniEnv, "Hi,I'm From C"); __android_log_print(ANDROID_LOG_INFO, "JNIMsg", "SayHello Begin" ); (*jniEnv)->CallVoidMethod(jniEnv, mTestProvider, sayHello,jstrMSG); __android_log_print(ANDROID_LOG_INFO, "JNIMsg", "SayHello End" ); (*jniEnv)->DeleteLocalRef(jniEnv, jstrMSG); }
最后再反调用java的方法
package com.duicky; public class TestProvider { public static String getTime() { LogUtils.printWithSystemOut( "Call From C Java Static Method" ); LogUtils.toastMessage(MainActivity.mContext, "Call From C Java Static Method" ); return String.valueOf(System.currentTimeMillis()); } public void sayHello(String msg) { LogUtils.printWithSystemOut("Call From C Java Not Static Method :" + msg); LogUtils.toastMessage(MainActivity.mContext, "Call From C Java Not Static Method :" + msg); } }