Kar*_*nek 8 java java-native-interface java-web-start
我正在使用Java Web Start来启动依赖于某些第三方本机库的Java应用程序.然后,这些本机库commonLib使用LoadLibrary/dlopen 加载另一个本机库()作为它们的依赖项.
不使用Web Start时,当本机库位于同一目录中时,一切都按预期工作.
但是,Web Start要求将本机库打包在jar文件中并在jnlp文件中引用,我这样做了:
<!-- Windows OS -->
<resources os="Windows">
<nativelib href="native/native-windows.jar" />
</resource>
<!-- Linux OS -->
<resources os="Linux">
<nativelib href="native/native-linux.jar" />
</resources>
<!-- Mac OSX -->
<resources os="Mac OS X">
<nativelib href="native/native-osx.jar"/>
</resources>
Run Code Online (Sandbox Code Playgroud)
本机库加载正常但它们无法加载它们的依赖项commonLib- C++ LoadLibrary/dlopen调用失败,因为该文件存在于某个jar/cache文件夹中而不是当前库搜索路径中.
在Windows上,我能够commonLib在尝试加载JNI库之前通过在Java中预加载来解决此问题,如下所示:
System.loadLibrary("commonLib");
System.loadLibrary("myNativeLib");
Run Code Online (Sandbox Code Playgroud)
但是,这种方法在OS X上不起作用 - 本机代码中的dlopen失败.dlopen显然不够聪明,如果它已经加载,不再尝试加载库.
是否有一种跨平台的方式来打包和加载依赖于Java Web Start中其他本机库的本机库?
我找到了一个(丑陋的)解决方法。诀窍是将依赖库(commonLib)打包到一个简单的资源jar中,并将其添加到jnlp文件中:
...
<resources os="Windows">
<jar href="native/deps-windows.jar" />
</resources>
<resources os="Linux">
<jar href="native/deps-linux.jar" />
</resources>
<resources os="Mac OS X">
<jar href="native/deps-osx.jar" />
</resources>
...
Run Code Online (Sandbox Code Playgroud)
第二步是使用 Java 将这些资源提取到临时目录中:
String tmpDir = System.getProperty("java.io.tmpdir");
if (!tmpDir.endsWith("/") && !tmpDir.endsWith("\\"))
tmpDir += "/";
String resource = "commonDir.dll"; // Adjust accordingly to current OS, omitted for brevity
InputStream is = loader.getResourceAsStream(resource);
if (is == null) {
// Handle error - resource not found
return;
}
try {
FileOutputStream os = new FileOutputStream(tmpDir + resource);
byte[] buffer = new byte[1024*1024];
int len = is.read(buffer);
while (len != -1) {
os.write(buffer, 0, len);
len = is.read(buffer);
}
os.close();
is.close();
System.out.println("Extracted " + resource + " to " + tmpDir);
} catch(IOException ex) {
// Handle the exception - cannot write to temp directory
System.out.println("Could not extract resource " + resource + " to " + tmpDir + ": " + ex.getMessage());
}
Run Code Online (Sandbox Code Playgroud)
第 3 步是通知本机 JNI 库有关提取的依赖项的完整路径,或者临时将当前目录设置为 temp 目录tmpDir,加载 JNI 库并将其设置回来。这本身就是一个问题 - 在 Java 中很难更改当前工作目录。您可以通过创建另一个小型实用程序 JNI 库来解决这个问题,该库从 C 语言中执行此操作 [ 1 ]。
| 归档时间: |
|
| 查看次数: |
2075 次 |
| 最近记录: |