C语言 JNI:将代码打包到自包含的二进制文件中

5anewei6  于 11个月前  发布在  其他
关注(0)|答案(1)|浏览(85)

我目前正在做一个java/C混合项目。因为我喜欢尽可能减少运行时障碍,所以我倾向于整合资源(图片)在我的二进制文件,从而消除了错误,如“图片找不到”,这可能会发生当用户移动我的二进制文件。(通过,例如C23 #embed或xxd)。通常,在现代机器上,达到几MB的二进制文件不再是问题。然后我可以通过(程序开头的一个简单的foreach循环)在我的C程序中加载类:

jclass DefineClass(JNIEnv *env, const char *name, jobject loader,
const jbyte *buf, jsize bufLen);

字符串
我的问题是:如何对整个jar文件执行此操作?我想在二进制文件中包含selenium API等?解压缩每个jar文件,将其包含在二进制文件中,并对它们进行定义是否足够?是否存在我可能遗漏的任何障碍?
编辑:我的切入点是在C端。事实上,整个应用程序不包含任何Java代码,它只是通过JNI使用了Selenium的一些API。

vltsax25

vltsax251#

作为一种完全不同的方法,为什么不滥用JARs底层的ZIP文件格式呢?ZIP文件将其元数据存储在文件的末尾,这意味着您可以简单地将ZIP文件附加到二进制文件中,运行嵌入式JVM,将二进制文件添加到自己的类路径中。添加整个selenium只是将所有内容重新打包到一个uberjar中。
举一个简单的例子,以Main.java为例:

class Main {
    public static void main(String[] args) {
        System.out.println("Hello from java");
    }
}

字符串
和jni.cpp:

#include <jni.h>
#include <string>

int main(int argc, char **argv) {
    JavaVM *jvm;       /* denotes a Java VM */
    JNIEnv *env;       /* pointer to native method interface */
    JavaVMInitArgs vm_args; /* JDK/JRE 6 VM initialization arguments */
    JavaVMOption* options = new JavaVMOption[1];
    std::string option = "-Djava.class.path=";
    option += argv[0];
    options[0].optionString = const_cast<char *>(option.c_str());
    vm_args.version = JNI_VERSION_1_6;
    vm_args.nOptions = 1;
    vm_args.options = options;
    vm_args.ignoreUnrecognized = false;
    /* load and initialize a Java VM, return a JNI interface
     * pointer in env */
    JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);
    delete[] options;
    /* invoke the Main.test method using the JNI */
    jclass cls = env->FindClass("Main");
    jmethodID mid = env->GetStaticMethodID(cls, "main", "([Ljava/lang/String;)V");
    env->CallStaticVoidMethod(cls, mid);
    /* We are done. */
    jvm->DestroyJavaVM();
}


然后,您可以:

$ make jni
$ javac Main.java
$ jar cf code.jar Main.java
$ cat jni code.jar > jni-combined
$ ./jni-combined
Hello from java

相关问题