在 .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
沒有留言:
張貼留言