1.前言
在开发Java应用的过程中,经常会遇到需要使用C/C++等Native语言编译的动态库或静态库,在这些情况下往往需要将预先编译好的各平台库文件与JAR包一同发布,鉴于简洁的原则,我们可能会希望将这些库文件打入JAR包中以使使用者部署变得更容易,但由于Java本身并不能正确寻找到位于JAR包中的库文件,所以本文就通过一个实例向大家讲解如何将库文件打入JAR包中。
2.准备
本文所使用实例代码基于Gradle构建,所以在下载实例代码前,请先确认已经正确配置了Java及Gradle,Gradle的配置仅需从官网下载gradle预编译包,然后配置其中bin目录到path环境变量即可。
本文例程Github地址:https://github.com/WeJoy/JNIJar
下载代码后,在项目路径下执行gradle命令:
esther-asus:JNIJar-master HalfmanG2$ ls README.md* build.gradle* src/
esther-asus:JNIJar-master HalfmanG2$ gradle release :compileJava :processResources :classes :copyData :release BUILD SUCCESSFUL Total time: 5.73 secs This build could be faster, please consider using the Gradle Daemon: https://docs.gradle.org/2.10/userguide/gradle_daemon.html
完成项目构建,然后进入生成的build/libs目录下,可以看到本例程编译后生成的JAR包,通过java执行之:
esther-asus:JNIJar-master HalfmanG2$ cd build/libs
esther-asus:libs HalfmanG2$ ls JNIJar1.0.0.jar doc/
esther-asus:libs HalfmanG2$ java -jar JNIJar1.0.0.jar JNIUtil: "/Users/HalfmanG2/Downloads/JNIJar-master/build/libs/libSnapshoot.so" is loaded! HelloWorld!
esther-asus:libs HalfmanG2$ ls JNIJar1.0.0.jar doc/ libSnapshoot.so
我们可以看到,在执行Jar包后,会输出Native代码中生成的HelloWorld!字串,表示成功加载了so库,在JAR包执行后,会自动在在JAR包所在路径生成一个so库,该库是JAR包自动识别当前环境后,从JAR包中对应环境的路径中复制出来的,下面我们就来详细讲解下本例程。
3.说明
本例程代码主要由以下几个部分构成:
src/main/conf/doc,改目录中包含了libSnapshoot.so库的C++源码,大家可以自行尝试编译
src/main/java/com.hjess.MainApp,例程的Main入口类
src/main/java/com.hjess.device.Snapshoot,libSnapshoot的JNI类,其中包含了一个byte[] getShoot()方法,从Native库中获取一个字串,也就是"HelloWorld!"。
src/main/java/com.hjess.utils.JARUtil,一个提供了帮助Java程序获取当前执行的JAR包文件所在绝对路径方法的工具类,另外也可以帮助获取JAR包名之类的一些其他方法。
src/main/java/com.hjess.utils.JNIUtil,本文的核心类,该类提供了判断当前JVM环境,并从当前执行的JAR包中,找到对应该JVM环境的native库,并复制到JAR包外,并加载之的工具方法。
src/main/resources,资源目录,其中所有内容都会被一起打入JAR包根目录中,本例程中,resources目录中放入了各个环境的预编译native库,注意环境目录名是代码中定死的,暂时不要随意更改,当然大家也可以通过修改JNIUtil的代码做一些调整,具体方法请自行参阅代码(超级简单的)。
build.gradle,gradle构建所需的脚本,其中主要包含了一个release方法,其功能是将src/main/conf的内容复制到build/libs中,并将java代码与src/main/resources中的内容一起打成JAR包,本脚也可以用于一些其他Java应用场景,或者也可以使用ShadowJar之类的Gradle插件进行JAR打包,原理基本类似。
4.结语
基本内容就是这些,如果大家觉得这个小项目还挺有用,请在Github星一个,另外,由于只是写个小工具,并未考虑很多适配情况,代码也较粗糙,欢迎大家帮忙修改,先行谢过~~