在 .i 檔,偷埋一些 function
MyNDK.i
%module MyNDK %{ #include "MyNDK.h" }% %include "MyNDK.h" %init %{ JavaVM* g_cached_jvm = NULL; JNIEnv* g_cached_env = NULL; jint JNI_OnLoad(JavaVM *vm, void *reserved) { g_cached_jvm = vm; if (vm->GetEnv((void**)&g_cached_env, JNI_VERSION_1_6) != JNI_OK) { return -1; } return JNI_VERSION_1_6; } JavaVM* JNI_GetVM() { return g_cached_jvm; } JNIEnv* JNI_GetEnv() { return g_cached_env; } %}
MyNDK.h
#ifndef __MY_NDK_H__ #define __MY_NDK_H__ #include <jni.h> const char* GetLocalStorageDir(jobject activity); #endif //__MY_NDK_H__
在 .cpp 檔裡,透過剛偷埋的 function ,就能拿到 JNIEnv or JavaVM 了
MyNDK.cpp
#include "MyNDK.h" #include <string> extern JNIEnv* JNI_GetEnv(); std::string gCachedLocalStorageDir; const char* GetLocalStorageDir(jobject activity) { JNIEnv* env = JNI_GetEnv(); jclass clsContext = env->FindClass("android/content/Context"); jclass clsFile = env->FindClass("java/io/File"); jmethodID midGetFilesDir = env->GetMethodID(clsContext, "getFilesDir","()Ljava/io/File;"); jmethodID midGetPath = env->GetMethodID(clsFile, "getPath","()Ljava/lang/String;"); jobject objFile = env->CallObjectMethod(activity, midGetFilesDir); jstring objPath = (jstring) env->CallObjectMethod(objFile, midGetPath); const char* path = env->GetStringUTFChars(objPath, NULL); gCachedLocalStorageDir = path; env->ReleaseStringUTFChars(objPath, path); return gCachedLocalStorageDir.c_str(); }
記住,如果是在 C/C++ layer create 的 pthread 裡,想呼叫 JNI 的 code,一定要 AttachCurrentThread,否則,可能會造成 AP crash!因為 JNIEnv* 只能在同一條 thread 取得與使用。不要試著拿 global 的 JNIEnv* 變數,因為可能是別條 thread 所 created 的,像上面的例子,就是 JNI_OnLoad() 時,拿到的 JNIEnv* ,不能給其他條 thread 所用。
AttachCurrentThread sample code :
bool ProcessJNISafe() { bool isDoAttach = false; JavaVM* jvm = JNI_GetVM(); JNIEnv* env = NULL; // Get JNIEnv & try Attach jint ret = jvm->GetEnv((void **)&env, JNI_VERSION_1_6); if( ret == JNI_EDETACHED ) { if( jvm->AttachCurrentThread(&env, NULL) < 0 ) return false; isDoAttach = true; } else if( ret != JNI_OK ) { return false; } // process JNI layer here { } // Detach if(isDoAttach) { jvm->DetachCurrentThread(); } return true; }
Reference:
- Android - JNI Tips
- SWIG - Initialization blocks
沒有留言:
張貼留言