1

Android C/C++ 原生调用 Java API 的例子很多。但是,我读过的所有这些示例都是 Android Java API 首先调用本机,然后本机通过使用传递的 JNI-ENV 调用其他 Java API。

没有通过的 JNI-ENV,C/C++ 怎么能得到呢?C/C++ 本机是否可以在没有 JNI-ENV 的情况下调用 Java API?

如果可能的话,你能举个例子或链接吗?

谢谢!

4

1 回答 1

3

您需要先包括在内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

完毕?现在事情变得更简单了:

  1. 初始化 JNI(以便您的代码使用正确的 VM)

    JniInvocation invocation;
    if (invocation.Init(nullptr)) return;
    
  2. 创建 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;
    
  3. 至此,您vm已经env可以使用了。玩得开心。

  4. 检查异常(如果有)

    if (env->ExceptionCheck()) {
        // ...
    }
    
  5. 完成后,清理

    vm->DetachCurrentThread();
    vm->DestroyJavaVM();
    

更多有趣的东西可以在这里找到,DalvikVM Main可能是最好的知识来源。祝你好运!

于 2015-11-26T19:27:45.853 回答