在Android 5.0中加载本地库时出现java.lang.UnsatisfiedLinkError错误

3

我正在通过以下方式加载我的本地库:

try {
       System.loadLibrary("myNative");
} catch (UnsatisfiedLinkError e) {
       //java.lang.UnsatisfiedLinkError here
       System.load("/data/data/com.my.app/app_native/libmyNative.so");
}

上述代码最终被打包成Jar文件。
在另一个项目中,我使用DexClassLoader加载上述Jar文件:
DexClassLoader dexClassLoader = new DexClassLoader(jarPath,
                    optJarPath,
                    getDir("native", Context.MODE_PRIVATE),
                    getClassLoader());

请注意,在构建此dexClassLoader实例时,我已指定本机代码所在的路径,即getDir("native", Context.MODE_PRIVATE)
(我正在使用NDK release 10生成本机库。当生成本机代码文件libmyNative.so时,我的Java代码(打包到最终Jar中)检查CPU体系结构类型并将正确的代码复制到getDir("native",Context.MODE_PRIVATE)。)
上述代码在除Android 5.0 Lollipop之外的其他设备上运行良好。在Android 5.0 Lollipop设备上运行时,我不断收到以下错误:
java.lang.UnsatisfiedLinkError: dlopen failed: "/data/data/com.my.app/app_native/libmyNative.so" is 32-bit instead of 64-bit
at java.lang.Runtime.load(Runtime.java:331)
at java.lang.System.load(System.java:982)

如何解决这个问题?

您似乎正在尝试在64位目标上使用32位库。如果您无法提供64位库,则必须说服Android回退到32位模式以适应该库。https://dev59.com/Lobca4cB1Zd3GeqPWX2W建议,如果安装程序仅检测到APK中的32位库,则会发生这种情况。如果您找不到另一种触发该模式的方法,则可能需要在实际APK中包含一个占位符32位库,以便安装程序看到并响应。最终,您能否提供64位库? - Chris Stratton
@ChrisStratton,谢谢您的评论,我需要在64位目标上运行我的32位库,这是我现在想要实现的目标。 - Leem.fin
1
那我建议您尝试在apk中放置一个虚拟的32位库。 - Chris Stratton
@ChrisStratton,1. 如果我想让系统加载我的真正的32位库,为什么我需要这个虚拟的32位库?我不明白。2. 我该如何创建一个虚拟的32位库? - Leem.fin
您已经在http://stackoverflow.com/questions/28992323/unsatisfiedlinkerror-on-android-5-0-lollipop上提出了这个问题。不允许重新发布。 - Chris Stratton
1个回答

1
您似乎正在尝试在64位目标上使用32位库。如果您无法提供64位库,则必须说服Android回退到32位模式以适应该库。
显然,兼容性模式(源代码似乎称其为ABI覆盖)通常在安装时设置,安装程序会发现只有32位(而不是64位)库可用。但在您的情况下,该库在安装时不可见,因此这种方法行不通。
如果您在apk中放置一个“虚拟”的32位库,该库最接近64位设备需求,那么系统将希望配置您的应用程序以在32位兼容性模式下运行,以便稍后加载您的真正的32位库实际上可以工作。
我不知道32位库是否需要是真正的库,还是一个具有正确位置和合理名称的空文件,但来自ndk样本文件夹的hello-jni项目的libhello-jni.so应该可以工作。您不需要任何相应的Java代码,只需要一个安装程序可以发现的本地库(但是,测试调用它可能不是一个坏主意)。
可能还有其他方式可以触发此操作,比如清单中的某些内容(尽管文档中没有提到)。我不太可能怀疑在运行时采取任何措施会起作用,因为此模式可能已经在您的代码运行之前被固定设置(看起来您实际上可能会在这样的系统上运行两个zygote实例,一个是64位的,另一个是32位的,其想法是应用程序由被认为是适当的那一个启动)。

  1. 在您的情况下,库在安装时不可见,为什么??
  2. 假的32位libt在APK中的路径是什么?<apk package>/libs/libmyNative.so ??
- Leem.fin
1
如果 真实 库存在 apk 中,则您正在完全错误的方式进行操作 - 您不应该自己复制本地库,而是让系统自动从 apk 复制它,并在调用 System.loadLibrary() 时自动找到结果。另一方面,如果真正的库毕竟没有出现在 apk 中(可能是因为您计划稍后下载它),则将虚拟库放在其 ABI 的传统目录中 - 即,完全按照 NDK 指令操作。 - Chris Stratton
谢谢,你是对的。 - Leem.fin
截至今天,使用最新的实验性Gradle和Android 2.1,在compileSdkVersion低于或等于19的情况下会阻止构建64位共享库,并且32位共享库不会安装在64位Android上。这很混乱,因为无法构建单个APK同时支持API 19以上和以下,尽管共享库在所有API版本上都可以正常工作,除了使用20/21+编译的共享库将根本无法在API 19及以下版本上工作,因为C库已更改。一团糟。 - 3c71
@3c71 - 不清楚你在说什么(Android 2.1?真的吗?),但无论如何,这不是讨论的正确场所 - 这个问题已经被关闭为重复,也就是说,这个页面实际上不应该存在。 - Chris Stratton
哈哈,确实,我是指的Android Studio 2.1。为了获取64位库,我不得不创建两个模块,都指向同一个src文件夹,一个使用compileSdkVersion 19,另一个使用compileSdkVersion 21。第一个将构建与API19及以下版本兼容的非64位库,而第二个将构建与API20及以上版本兼容的64位库。是的,没看到它已经关闭了。 - 3c71

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接