如何在JAR中绑定本地库和JNI库?

有问题的图书馆是东京内阁 。

我想要的是将本机库,JNI库和所有Java API类放在一个JAR文件中,以避免重新分配头痛。

GitHub似乎有这个尝试 ,但是

  1. 它不包括实际的本地库,只包括JNI库。
  2. 这似乎是特定于Leiningen的本地依赖项插件(它不会作为一个可再发行组件)。

问题是,我可以将所有东西都捆绑在一个JAR中并重新分配吗? 如果是的话,怎么样?

PS:是的,我意识到它可能具有可移植性。

https://www.adamheinrich.com/blog/2012/12/how-to-load-native-jni-library-from-jar/

是伟大的文章,这解决了我的问题..

在我的情况下,我有以下代码初始化库:

static { try { System.loadLibrary("crypt"); // used for tests. This library in classpath only } catch (UnsatisfiedLinkError e) { try { NativeUtils.loadLibraryFromJar("/natives/crypt.dll"); // during runtime. .DLL within .JAR } catch (IOException e1) { throw new RuntimeException(e1); } } } 

看看One-JAR 。 它会将你的应用程序包装在一个jar文件中,并且有一个专门的类加载器,可以处理“jar子里面的jar子”等等。

它通过将它们解压缩到临时工作文件夹来处理本地(JNI)库 。

(免责声明:我从来没有使用One-JAR,现在还没有需要,只是把它放在一个雨天collections。)

JarClassLoader是一个类加载器,用于从怪物JAR中加载类,本地库和资源,以及从怪物JAR中加载JAR。

您可能必须将本地库解压到本地文件系统。 据我所知,本地加载的代码位查看文件系统。

这段代码应该可以帮助你开始工作(我没有时间看它,这是为了一个不同的目的,但应该做的伎俩,我现在很忙,但如果你有问题,只留下评论我会尽快回答)。

 import java.io.Closeable; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.net.URLDecoder; import java.security.CodeSource; import java.security.ProtectionDomain; import java.util.zip.ZipEntry; import java.util.zip.ZipException; import java.util.zip.ZipFile; public class FileUtils { public static String getFileName(final Class<?> owner, final String name) throws URISyntaxException, ZipException, IOException { String fileName; final URI uri; try { final String external; final String decoded; final int pos; uri = getResourceAsURI(owner.getPackage().getName().replaceAll("\\.", "/") + "/" + name, owner); external = uri.toURL().toExternalForm(); decoded = external; // URLDecoder.decode(external, "UTF-8"); pos = decoded.indexOf(":/"); fileName = decoded.substring(pos + 1); } catch(final FileNotFoundException ex) { fileName = null; } if(fileName == null || !(new File(fileName).exists())) { fileName = getFileNameX(owner, name); } return (fileName); } private static String getFileNameX(final Class<?> clazz, final String name) throws UnsupportedEncodingException { final URL url; final String fileName; url = clazz.getResource(name); if(url == null) { fileName = name; } else { final String decoded; final int pos; decoded = URLDecoder.decode(url.toExternalForm(), "UTF-8"); pos = decoded.indexOf(":/"); fileName = decoded.substring(pos + 1); } return (fileName); } private static URI getResourceAsURI(final String resourceName, final Class<?> clazz) throws URISyntaxException, ZipException, IOException { final URI uri; final URI resourceURI; uri = getJarURI(clazz); resourceURI = getFile(uri, resourceName); return (resourceURI); } private static URI getJarURI(final Class<?> clazz) throws URISyntaxException { final ProtectionDomain domain; final CodeSource source; final URL url; final URI uri; domain = clazz.getProtectionDomain(); source = domain.getCodeSource(); url = source.getLocation(); uri = url.toURI(); return (uri); } private static URI getFile(final URI where, final String fileName) throws ZipException, IOException { final File location; final URI fileURI; location = new File(where); // not in a JAR, just return the path on disk if(location.isDirectory()) { fileURI = URI.create(where.toString() + fileName); } else { final ZipFile zipFile; zipFile = new ZipFile(location); try { fileURI = extract(zipFile, fileName); } finally { zipFile.close(); } } return (fileURI); } private static URI extract(final ZipFile zipFile, final String fileName) throws IOException { final File tempFile; final ZipEntry entry; final InputStream zipStream; OutputStream fileStream; tempFile = File.createTempFile(fileName.replace("/", ""), Long.toString(System.currentTimeMillis())); tempFile.deleteOnExit(); entry = zipFile.getEntry(fileName); if(entry == null) { throw new FileNotFoundException("cannot find file: " + fileName + " in archive: " + zipFile.getName()); } zipStream = zipFile.getInputStream(entry); fileStream = null; try { final byte[] buf; int i; fileStream = new FileOutputStream(tempFile); buf = new byte[1024]; i = 0; while((i = zipStream.read(buf)) != -1) { fileStream.write(buf, 0, i); } } finally { close(zipStream); close(fileStream); } return (tempFile.toURI()); } private static void close(final Closeable stream) { if(stream != null) { try { stream.close(); } catch(final IOException ex) { ex.printStackTrace(); } } } }