折腾了两天总算搞定c调用jar包,其中遇到的问题这里总结一下: 1、起始demo 参考C调用java例子先跑起来 2、开发环境 使用linux虚拟机效率很低,找到了gnuwin32实现在windows下运行Makefile,使用的是https://sourceforge.net/projects/gnuwin32/ ,只需要把 mingw32-make.exe文件改名为make.exe 3、java开发 直接使用eclipse生成一个mvn项目,以这个最简项目开始入手 使用mvn编译出jar给c调用,参考maven将所有的依赖打成一个包,确保依赖没有问题,验证方法:
代码语言:javascript复制java -cp mytest.jar com.test.mytest.App
能够执行成功(jar复制到c文件同一个目录,不成功估计是第7条的问题) 4、jar的调用 options.optionString ="-Djava.class.path=.;mytest.jar"; 这个参数里面的分号不能搞错,否则总是找不到java的类 5、java函数返回值只能是string 其他类型一定得不到返回值,只好老老实实把其他类型转换为string返回 6、java函数执行异常返回值也拿不到 好的习惯是给java代码增加try catch,并且打印异常错误,从而能够快速发现问题,否则就是干着急也看不出问题在哪里,5和6两个问题基本耗费了我一天时间才解决 7、jvm.dll找不到的问题 直接把jvm.dll所在的路径添加到path就可以了 8、如果异常出现并显示java的crash堆栈 估计是函数的参数传递错误了,或者少传参数了 9、linux下和windows的区别有两个 编译命令要改一下:
代码语言:javascript复制gcc -I/usr/lib/jvm/jdk1.8.0_111/include -I/usr/lib/jvm/jdk1.8.0_111/include/linux -o hello_world hello_world.c -L/usr/lib/jvm/jdk1.8.0_111/jre/lib/amd64/server -ljvm -D__int64="long long"
另外c代码里面改一句话
代码语言:javascript复制options.optionString ="-Djava.class.path=.;mytest.jar";
修改为:
代码语言:javascript复制options.optionString ="-Djava.class.path=.:mytest.jar";
这里附上c的代码,java代码就自己脑补
代码语言:javascript复制#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include<jni.h>
JNIEnv* create_vm(JavaVM **jvm)
{
JNIEnv* env;
JavaVMInitArgs args;
JavaVMOption options;
args.version = JNI_VERSION_1_6;
args.nOptions = 1;
options.optionString ="-Djava.class.path=.;mytest.jar";
args.options = &options;
args.ignoreUnrecognized = 0;
int rv;
rv = JNI_CreateJavaVM(jvm,(void**)&env, &args);
if (rv < 0 || !env)
printf("Unable to Launch JVM%dn",rv);
else
printf("Launched JVM! :)n");
return env;
}
void invoke_class(JNIEnv* env)
{
jclass clazz;
jmethodID main_method;
jmethodID square_method;
jmethodID power_method;
jint number=20;
jint exponent=3;
clazz =(*env)->FindClass(env, "com/test/mytest/App");
if(clazz == NULL) {
printf("can't find hello_world_class");
return;
}
// 这里调用main
main_method =(*env)->GetStaticMethodID(env, clazz, "main","([Ljava/lang/String;)V");
if(main_method == NULL) {
printf("can't find main_methodn");
return;
}
(*env)->CallStaticVoidMethod(env,clazz, main_method, NULL);
// 这里调用public static String abiEncode(String abi, String data)
jstring str = (*env)->NewStringUTF(env,"{ "constant":false, "inputs":[{"name":"i","type":"int"}, {"name":"s","type":"string"}, {"name":"j","type":"int"}], "name":"f4", "outputs":[{"name":"i","type":"int"}, {"name":"s","type":"string"}, {"name":"j","type":"int"}], "type":"fallback" }");
printf("jstring strn");
jstring str2 = (*env)->NewStringUTF(env,"111, "aaa", 222");
printf("jstring str2n");
jmethodID abiEncode_method =
(*env)->GetStaticMethodID(env, clazz, "abiEncode","(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;");
if (abiEncode_method == NULL) {
printf("can't find abiEncode_methodn");
return; /* method not found */
}
jstring result = (*env)->CallStaticObjectMethod(env, clazz, abiEncode_method,str,str2);
printf("jbyteArray arr %xn",result);
if (result == NULL) {
printf("can't call abiEncode_methodn");
return; /* method not found */
}
const char *message = (*env)->GetStringUTFChars(env, result, NULL);
if (NULL == message) return;
printf("In C, the returned string is %sn", message);
(*env)->ReleaseStringUTFChars(env, result, message);
(*env)->DeleteLocalRef(env,str2);
(*env)->DeleteLocalRef(env,str);
(*env)->DeleteLocalRef(env,clazz);
}
int main(int argc,char **argv)
{
JavaVM *jvm;
JNIEnv *env;
env = create_vm(&jvm);
if(env == NULL)
return 1;
invoke_class(env);
return 0;
}
如果不用Makefile就直接用下面的命令编译:
代码语言:javascript复制gcc -I"C:/Program Files/Java/jdk1.8.0_101/include/" -I"C:/Program Files/Java/jdk1.8.0_101/include/win32" -o hello_world hello_world.c -L"C:/Program Files/Java/jdk1.8.0_101/jre/bin/server" -ljvm -D__int64="long long"