Android C/C++ 原生调用 Java API 的例子很多。但是,我读过的所有这些示例都是 Android Java API 首先调用本机,然后本机通过使用传递的 JNI-ENV 调用其他 Java API。
没有通过的 JNI-ENV,C/C++ 怎么能得到呢?C/C++ 本机是否可以在没有 JNI-ENV 的情况下调用 Java API?
如果可能的话,你能举个例子或链接吗?
谢谢!
Android C/C++ 原生调用 Java API 的例子很多。但是,我读过的所有这些示例都是 Android Java API 首先调用本机,然后本机通过使用传递的 JNI-ENV 调用其他 Java API。
没有通过的 JNI-ENV,C/C++ 怎么能得到呢?C/C++ 本机是否可以在没有 JNI-ENV 的情况下调用 Java API?
如果可能的话,你能举个例子或链接吗?
谢谢!
您需要先包括在内jni.h
。这带来了大量有用的调用;对于较新的 android 版本,您还需要JniInvocation.h
. 要启用此功能:
LOCAL_C_INCLUDES += ${JNI_H_INCLUDE}
这当然适用于源代码树,不确定 NDK,但也应该没问题。
其次,非常重要的是选择适当的信号链库。Art 或 Dalvik 将加载 libsigchain.so,它是一个存根,abort()
每次调用它的任何方法时都是 s。在 Android 上,它通过一些小技巧完成:局部符号被导出到全局符号表,以便 Art 选择 exec 的符号而不是加载共享库。这是如何完成的:
# Enable native helper calls
LOCAL_SHARED_LIBRARIES += libnativehelper
# Include all of the Android's libsigchain symbols
LOCAL_WHOLE_STATIC_LIBRARIES += libsigchain
# Export only libsigchain symbols to global symbol table.
LOCAL_LDFLAGS += \
-Wl,--export-dynamic \
-Wl,--version-script,art/sigchainlib/version-script.txt
现在链接您的可执行文件。仔细检查是否确实导出了所需的符号:
% readelf -a <output_binary> | grep InitializeSignalChain
654: 0002cab1 211 FUNC GLOBAL PROTECTED 12 InitializeSignalChain
完毕?现在事情变得更简单了:
初始化 JNI(以便您的代码使用正确的 VM)
JniInvocation invocation;
if (invocation.Init(nullptr)) return;
创建 JavaVM:
JavaVM* vm;
JNIEnv* env;
JavaVMInitArgs* args;
args.version = JNI_VERSION_1_4; // _5, _6
args.options = nullptr;
args.nOptions = 0;
args.ignoreUnrecognized = JNI_FALSE;
if (JNI_CreateJavaVM(&vm, &env, &args) < 0) return;
至此,您vm
已经env
可以使用了。玩得开心。
检查异常(如果有)
if (env->ExceptionCheck()) {
// ...
}
完成后,清理
vm->DetachCurrentThread();
vm->DestroyJavaVM();
更多有趣的东西可以在这里找到,DalvikVM Main可能是最好的知识来源。祝你好运!