本文基于jdk1.8版本,操作系统版本:mac os 10.14.6
最近研究项目需要在OS上编译JNI的动态库,网上找了些资料写得都不太尽人意,所以我自己写了篇文章备忘
Mac下 java jni c call 实现步骤:
我们先编写native方法类SystemInfo.java
这里面我们实现两个方法sayHello和getInfoId。
package com.xniax.jni;
public class SystemInfo {
private static final String LIBSYS = "sysmodule"; //要加载的模块名,自定义
public native void sayHello(); //本地方法,由c去实现
public native String getInfoId(); //本地方法,由c去实现
private static final SystemInfo instance = new SystemInfo();
private SystemInfo(){
}
static {
System.loadLibrary(LIBSYS);
}
public static SystemInfo getInstance(){
return instance;
}
}
然后写一个调用测试用的类Run.java
package com.xniax.jni;
public class Run {
public static void main(String[] args) {
System.out.println(System.getProperty("java.library.path"));
SystemInfo.getInstance().sayHello();
String infoId = SystemInfo.getInstance().getInfoId();
System.out.println("获取到的infoId为:"+infoId);
}
}
到SystemInfo.java所在目录:
javac SystemInfo.java
生成SystemInfo.class文件
然后到包的起始目录,也就是com的上一级目录执行
javah com.xniax.jni.SystemInfo
会在当前目录生成一个com_xniax_jni_SystemInfo.h文件
如果提示找不到SystemInfo类,一定是javah运行的位置有错,仔细核对
下一步编写c实现类
cp com_xniax_jni_SystemInfo.h到../c/com/xniax/jni/目录,我这里c目录是在com目录的上级目录。
到../c/com/xniax/jni/编写C实现类SystemInfoImpl.c
相应的代码目录结构图如下:
SystemInfoImpl.c实现类内容:
#include "jni.h"
#include "com_xniax_jni_Systeminfo.h"
#include <string.h>
#include <stdio.h>
char* getEnCode(){
char* s = "c created id string, qiduwei20220316";
return s;
}
JNIEXPORT void JNICALL Java_com_xniax_jni_SystemInfo_sayHello(JNIEnv *env,jobject obj){
printf("Hello sir!\n");
return;
}
JNIEXPORT jstring JNICALL Java_com_xniax_jni_SystemInfo_getInfoId(JNIEnv *env,jobject obj){
return (*env)->NewStringUTF(env, getEnCode());
}
将SystemInfoImpl.c生成动态链接:
gcc命令如下,如果没有gcc,请自行安装。-I后面的参数根据你电脑上对应jdk的相对路径来设置,注意-o参数设置的动态链接库名称一定是lib后面跟之前在SystemInfo定义的System.loadLibrary的模块名称,再跟.jnilib
gcc -dynamiclib -I /Library/Java/JavaVirtualMachines/jdk1.8.0_20.jdk/Contents/Home/include SystemInfoImpl.c -o libsysmodule.jnilib
生成 libsysmodule.jnilib 即为动态链接库
如果提示fatal error: 'jni_md.h' file not found
用下面命令拷贝一份过去
sudo cp /Library/Java/JavaVirtualMachines/jdk1.8.0_20.jdk/Contents/Home/include/darwin/jni_md.h /Library/Java/JavaVirtualMachines/jdk1.8.0_20.jdk/Contents/Home/include
将libsysmodule.jnilib拷贝到java.library.path中的一个路径中,如果不知道可以在java程序中打印System.getProperty("java.library.path")看看
比如我这边的路径是 /Library/Java/Extensions/:
sudo mv libsysmodule.jnilib /Library/Java/Extensions/
测试
运行我们刚才编写的Run.java直接可以看结果: