1、编写native接口
package org.demo; public class JniDemo { public static native int bmp2fea(byte[] bmp, byte[] fea, byte[] err); public static native int feaMatch(byte[] fea1, byte[] fea2, String flag, int level); }
2、根据native接口生成声明文件(.h)
javah -classpath . -jni org.demo.JniDemo
3、编写接口代码调动so动态库(.c)#include <stdlib.h>
#include <stadio.h> #include <string.h> #include 'org_demo_JniDemo.h' extern int feaMatch(char *pRegAscii, char *pVerAscii, int level); extern int bmp2fea(unsigned char* bmp, char* feature, char* flag, char* errinfo); JNIEXPORT jint JNICALL JAVA_org_demo_JniDemo_bmp2fea (JNIEnv *env, jclass arg, jbyteArray bmp, jbyteArray fea, jbyteArray err) { char out[1024] = { 0 }; char errinfo[1024] = { 0 }; jbyte* pbmp = (*env)->GetByteArrayElements(env, bmp, 0); jsize inSize = (*env)->GetArrayLength(env, bmp); //bmp大小平均150k,使用malloc //char *tmp = (char*)malloc(inSize + 1); //memset(tmp, 0, inSize+1);
char *tmp = (char*)calloc(inSize+1, sizeOf(char));
if (tmp == NULL)
{
(*env)->ThrowNew(env,
(*env)->FindClass(env, "java/lang/OutOfMemoryError"), "jni calloc failed");
return;
} memcpy(tmp, pbmp, inSize); int ret = bmp2fea((unsigned char*)tmp, (char*)out, (char*)errinfo); if (ret == 0) { (*env)->SetByteArrayRegion(env, fea, 0, strlen(out), (jbyte*)out); if (strlen(errinfo) > 0) (*env)->SetByteArrayRegion(env, err, 0, strlen(errinfo), (jbyte*)out); } else { if (strlen(errinfo) > 0) (*env)->SetByteArrayRegion(env, err, 0, strlen(errinfo), (jbyte*)out); } if (tmp != NULL) { free(tmp); } (*env)->ReleaseByteArrayElements(env, bmp, pbmp, JNI_ABORT); return rt; } JNIEXPORT jint JNICALL Java_org_demo_JniDemo_feaMatch (JNIEnv *env, jclass arg, jbyteArray fea1, jbyteArray fea2, jstring flag, jint level) { char tmp1[1024] = { 0 }; char tmp2[1024] = { 0 }; jbyte* pFea1 = (*env)->GetByteArrayElements(env, fea1, 0); jsize inSize1 = (*env)->GetArrayLength(env, fea1); memcpy(tmp1, pFea1, inSize1); jbyte* pFea2 = (*env)->GetByteArrayElements(env, fea2, 0); jsize inSize2 = (*env)->GetArrayLength(env, fea2); memcpy(tmp2, pFea2, inSize2);
char* pflag = (char*)(*env)->GetStringUTFChars(env, flag, 0); int ret = feaMatch(tmp1, tmp2, pflag, level); (*env)->ReleaseByteArrayElements(env, fea1, pFea1, JNI_ABORT); (*env)->ReleaseByteArrayElements(env, fea1, pFea2, JNI_ABORT);
(*env)->ReleaseStringUTFChars(env, flag, pflag); return ret; }
4、根据.h、.c编译生成so,如下makefie文件make生成libengine.so
ODIR=. EDIR=. LDIR=. INC_DIR=./ CC=g++ AR=ar -r LD=ld RM=rm -rf cc=gcc STRIP=strip MKDIR=mkdir -p INCLUDES=-I$(INC_DIR) CCFLAGS=-g $(INCLUDES) -fPIC LIBS=-lc -ldl -ldemo SRC_DIR=./ ALL_DIR=-I$(SRC_DIR) -I/usr/java/jdk1.7.0_80/include/ -I/usr/java/jdk1.7.0_80/include/linux/ LIBAPI_SO=$(LDIR)/libengine.so BIZD=$(EDIR)/test PROGRAM=$(LIBAPI_SO) ####object files#### LIBAPI_OBJ=$(ODIR)/org_demo_JniDemo.o ####object files#### BIZ_OBJ=$(ODIR)/test.o ############## all:$(PROGRAM) force: $(LIBAPI_SO)::$(LIBAPI_OBJ) @echo ----Linking...---- $(LD) -share -o $(LIBAPI_SO) $(LIBAPI_OBJ) -L./ $(LIBS) @echo ----make $@ OK---- $(BIZD)::$(BIZ_OBJ) @echo ----Linking...---- $(cc) -o $(BIZD) $(BIZD_OBJ) -L$(LDIR) $(LIBS) $(CCFLAGS) @echo ----make $@ OK---- clean:: @$(RM) $(ODIR)/*.o $(PROGRAM) cleanobj:: @$(RM) $(BIZ_OBJ) cleanbin:: @$(RM) $(PROGRAM) .SUFFIXES:.cpp .c .o .so .a ####common##### $(ODIR)/%.o:$(SRC_DIR)/%.c $(cc) $(CCFLAGS) $< $(ALL_DIR) -c -o $@
5、java调用native接口
package org.demo; import org.demo.JniDemo; public class Demo { static { // 动态库名: libdemo.so System.loadLibrary("demo"); // libengine.so System.loadLibrary("engine"); } public static int bmp2fea(byte[] bmp, byte[] fea, byte[] err) { return JniDemo.bmp2fea(bmp, fea, err); } public static int feaMatch(byte[] fea1, byte[] fea2,String flag, int level) { return JniDemo.feaMatch(fea1, fea2, flag, level); } }
6、配置动态库路径
方法一:
#linux用户环境变量配置:
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/demo/lib/
方法二:
#程序启动是配置JVM参数:
java -Djava.library.path=/demo/lib/ -server -cp $CLASSPATH org.demo.Test