1.创建xxx.jni包并在该包下实现一些Java的方法,和要调用的本地方法
2.实现MainActivity中的按钮点击事件—即点击按钮调用本地的方法
3.在C文件中的方法中回调Java的方法
3.1:通过env获取字节码对象—>jclass (*FindClass)(JNIEnv*, const char*)
第二个参数为要回调Java方法所在类的全路径如:jclass claz = (*env)->FindClass(env, "com/rocky/jniccallbackdemo/jni/JNI");
3.2:通过字节码对象获取方法ID—>jmethodID (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);
第二个参数是由3.1获取的字节码对象,第三个对象是要回调的Java方法名,第四个参数该Java方法签名,因为Java中有重载,需要此参数确定具体是哪个方法如:jmethodID methodId = (*env)->GetMethodID(env, claz, "helloFromJava", "()V")
注:对应方法签名,需要到工程目录下的bin/classes目录下执行:javap -s com.rocky.jniccallbackdemo.jni.JNI(该方法所在类的全类名)
3.3:通过字节码对象创建Java对象—>jobject (*AllocObject)(JNIEnv*, jclass);
如:jobject obj = (*env)->AllocObject(env, claz);
注:如果本地方法和要回调的Java方法在同一个类中,则第二参数就是本地方法传过来的第二个参数,即第三步可以可以省略。
3.4:通过Java对象回调Java方法
调用Java的无返回值方法:void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...),如: (*env)->CallVoidMethod(env, clazz, methodId);
DEMO:
JNI.java
public class JNI { static { System.loadLibrary("callback"); } private Context mContext = null; public JNI(Context context) { this.mContext = context; } public void helloFromJava() { System.out.println("Hello From Java"); } public void printString(String str) { System.out.println(str); } public void showToast(String str) { Toast.makeText(mContext, str, Toast.LENGTH_SHORT).show(); } public native void callbackVoidMethod(); public native void callbackStringMethod(); public native void callbackIntMethod(); public native void callbackShowToastMethod(); }
MainActivity.java
public class MainActivity extends Activity implements OnClickListener { Context mContext = null; Button bt_callback_void = null; Button bt_callback_string = null; Button bt_callback_int = null; Button bt_callback_toast = null; JNI jni = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mContext = this; jni = new JNI(mContext); bt_callback_void = (Button) findViewById(R.id.bt_callback_void); bt_callback_void.setOnClickListener(this); bt_callback_int = (Button) findViewById(R.id.bt_callback_int); bt_callback_int.setOnClickListener(this); bt_callback_string = (Button) findViewById(R.id.bt_callback_string); bt_callback_string.setOnClickListener(this); bt_callback_toast = (Button) findViewById(R.id.bt_callback_toast); bt_callback_toast.setOnClickListener(this); } public int add(int x, int y) { return x + y; } @Override public void onClick(View v) { switch (v.getId()) { case R.id.bt_callback_void: jni.callbackVoidMethod(); break; case R.id.bt_callback_int: jni.callbackIntMethod(); break; case R.id.bt_callback_string: jni.callbackStringMethod(); break; case R.id.bt_callback_toast: jni.callbackShowToastMethod(); break; default: break; } } }
callback.c
#include <jni.h> #include <android/log.h> #define LOG_TAG "rocky" #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__) #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__) #define LOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__) #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__) #define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__) JNIEXPORT void JNICALL Java_com_rocky_jniccallbackdemo_jni_JNI_callbackVoidMethod (JNIEnv *env, jobject clazz) { //1.获取字节码对象 jclass (*FindClass)(JNIEnv*, const char*); jclass claz = (*env)->FindClass(env, "com/rocky/jniccallbackdemo/jni/JNI"); //2.通过字节码对象获取方法ID jmethodID (*GetMethodID)(JNIEnv*, jclass, const char*, const char*); jmethodID methodId = (*env)->GetMethodID(env, claz, "helloFromJava", "()V"); //3.通过字节码对象创建Java对象(此处因为本地方法和回调方法在同一个类中,可以省略) //4.通过Java对象回调Java方法 void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...); (*env)->CallVoidMethod(env, clazz, methodId); } /* * Class: com_rocky_jniccallbackdemo_jni_JNI * Method: callbackIntMethod * Signature: ()V */ JNIEXPORT void JNICALL Java_com_rocky_jniccallbackdemo_jni_JNI_callbackIntMethod (JNIEnv *env, jobject clazz) { jclass claz = (*env)->FindClass(env, "com/rocky/jniccallbackdemo/MainActivity"); jmethodID methodId = (*env)->GetMethodID(env, claz, "add", "(II)I"); //3.通过字节码对象创建Java对象(此处为MainActivity对象) jobject (*AllocObject)(JNIEnv*, jclass); // jobject obj = (*env)->AllocObject(env, claz); //4.通过Java对象回调Java方法 void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...); jobject obj = (*env)->AllocObject(env, claz); jint res = (*env)->CallIntMethod(env, obj, methodId, 8, 9); LOGI("res = %d\n", res); } JNIEXPORT void JNICALL Java_com_rocky_jniccallbackdemo_jni_JNI_callbackStringMethod (JNIEnv *env, jobject clazz) { jclass claz = (*env)->FindClass(env, "com/rocky/jniccallbackdemo/jni/JNI"); jmethodID methodId = (*env)->GetMethodID(env, claz, "printString", "(Ljava/lang/String;)V"); jstring result = (*env)->NewStringUTF(env, "cccccccccccccc"); (*env)->CallVoidMethod(env, clazz, methodId, result); } JNIEXPORT void JNICALL Java_com_rocky_jniccallbackdemo_jni_JNI_callbackShowToastMethod (JNIEnv *env, jobject clazz) { jclass claz = (*env)->FindClass(env, "com/rocky/jniccallbackdemo/jni/JNI"); jmethodID methodId = (*env)->GetMethodID(env, claz, "showToast", "(Ljava/lang/String;)V"); jstring result = (*env)->NewStringUTF(env, "rocky--------rocky"); (*env)->CallVoidMethod(env, clazz, methodId, result); }
Android.mk
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := callback LOCAL_SRC_FILES := callback.c LOCAL_LDLIBS += -llog include $(BUILD_SHARED_LIBRARY)