折腾了两天总算搞定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将所有的依赖打成一个包,确保依赖没有问题,验证方法:
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的区别有两个
编译命令要改一下:
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代码里面改一句话
options.optionString ="-Djava.class.path=.;mytest.jar";
修改为:
options.optionString ="-Djava.class.path=.:mytest.jar";
这里附上c的代码,java代码就自己脑补
#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%d\n",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_method\n");
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 str\n");
jstring str2 = (*env)->NewStringUTF(env,"111, \"aaa\", 222");
printf("jstring str2\n");
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_method\n");
return; /* method not found */
}
jstring result = (*env)->CallStaticObjectMethod(env, clazz, abiEncode_method,str,str2);
printf("jbyteArray arr %x\n",result);
if (result == NULL) {
printf("can't call abiEncode_method\n");
return; /* method not found */
}
const char *message = (*env)->GetStringUTFChars(env, result, NULL);
if (NULL == message) return;
printf("In C, the returned string is %s\n", 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就直接用下面的命令编译:
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"
网友评论