android java 與 c++ 相互呼叫的方法
阿新 • • 發佈:2019-01-10
android java 與 c++ 相互呼叫的方法
最近在寫native部分的程式碼,需要c++和java相互呼叫。記得JK之前說過他弄了一個新的方法,在寫jni的時候會自由一點,我對了一下他的程式碼,根據我的場景寫了一個出來。在這裡給自己做一點筆記吧。
Android.mk
LOCAL_MODULE := SDKBridge_shared LOCAL_MODULE_FILENAME := libSDKBridge LOCAL_SRC_FILES := $(LOCAL_PATH)/hellocpp/sdk_bridge.cpp LOCAL_CPPFLAGS += -fexceptions # enable try...catch LOCAL_LDLIBS := -llog # enable android logcat include $(BUILD_SHARED_LIBRARY)
如果要引用自己的so庫的時候
LOCAL_SHARED_LIBRARIES := SDKBridge_shared
java層中這樣引用這個庫
package org.cocos2dx.cpp;
public class SDKBridge {
static {
System.loadLibrary("SDKBridge");
}
public static void quit() {
Log.d(TAG, "Java quit");
AppActivity ac = AppActivity.getActivity ();
if (ac != null) ac.quit();
}
public static native void _init();
public static native void _onQuit();
}
重點就是在 cpp 中的 JNI_OnLoad 的方法,這樣設計
sdk_bridge.cpp
#include <android/log.h> #include <stdio.h> #include <jni.h> #include <cstdlib> #include "sdk_bridge.h" #include "stddef.h" #define LOG_TAG "SDKBridge" #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__) #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 JAVA_SDK_CLASS_PATH "org/cocos2dx/cpp/SDKBridge" namespace sdk { JavaVM *_vm = NULL; jclass _sdk_bridge_cls = NULL; jmethodID _sdk_quit = NULL; void check_jni_ready(JNIEnv *env) { if (NULL == env || NULL == _sdk_bridge_cls || NULL == _sdk_login || NULL == _sdk_logout || NULL == _sdk_pay || NULL == _sdk_quit) { LOGE("jni is not ready! init error!"); abort(); } } JNIEnv *getEnv() { if (NULL == _vm) { LOGE("jni is not ready! Please call _init first!"); abort(); } JNIEnv *env; _vm->AttachCurrentThread(&env, nullptr); return env; } void java_quit(JNIEnv *env) { check_jni_ready(env); env->CallStaticVoidMethod(_sdk_bridge_cls, _sdk_quit); } void native_init(JNIEnv *env) { LOGI("init"); } void native_on_quit() { LOGE("TODO:native on quit"); if (NULL != sCallbackFunction) { sCallbackFunction("onQuit",""); } } } JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *unused) { JNIEnv *env = NULL; jclass sdk_bridge_cls; static JNINativeMethod methods[] = { {"_init", "()V", (void *) sdk::native_init}, {"_onQuit", "()V", (void *) sdk::native_on_quit} }; if ((*vm).GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) { LOGE("get env error, abort!"); abort(); } sdk_bridge_cls = env->FindClass(JAVA_SDK_CLASS_PATH); if (!sdk_bridge_cls) { LOGE("native registration unable to find class '%s'!", JAVA_SDK_CLASS_PATH); abort(); } if (env->RegisterNatives(sdk_bridge_cls, methods, sizeof(methods) / sizeof(methods[0])) < 0) { LOGE("native registration failed!"); abort(); } sdk::_sdk_login = env->GetStaticMethodID(sdk_bridge_cls, "quit", "()V"); if (!sdk::_sdk_login) { LOGE("can not get login method id!"); abort(); } sdk::_vm = vm; sdk::_sdk_bridge_cls = (jclass) env->NewGlobalRef(sdk_bridge_cls); (*env).DeleteLocalRef(sdk_bridge_cls); return JNI_VERSION_1_6; }
sdk_bridge.h
#ifndef PROJ_ANDROID_SDK_BRIDGE_H
#define PROJ_ANDROID_SDK_BRIDGE_H
#include <jni.h>
#include <string>
namespace sdk {
typedef void (*OnJavaCallback)(std::string, std::string);
OnJavaCallback sCallbackFunction = NULL;
void register_print(OnJavaCallback callback) {
sCallbackFunction = callback;
}
JNIEnv *getEnv();
void java_quit(JNIEnv *env);
}
#endif //PROJ_ANDROID_SDK_BRIDGE_H
一個注意點就是 JNIEnv 不能做快取,能快取的只有 JavaVM