想必很多开发者和我们一样,遇到过许多UnsatisfiedLinkError的困难,着实令人头疼,现在总结一下,希望能帮助更多的人。

常见错误

  • lib库不同目录下的SO文件参差不齐。
  • lib库目录下的SO不符合相应的CPU架构。
  • 64-bit下使用System.load加载SO:"lib_xyz.so" is 32-bit instead of 64-bit
  • java代码混淆导致。
  • 注册方式不对,或已经被其他类注册。
  • empty/missing DT_HASH in "libxxxx.so" (built with --hash-style=gnu?)

出错现象及解决方案

  • lib库不同目录下的SO文件参差不齐。

    发现很多APK包打出来,lib目录下同时带着armeabi、armeabi-v7a,但是armeabi目录下可能有3个SO,而armeabi-v7a下只有2个SO,更有甚者还有armeabi、armeabi-v7a、x86、x86_64、arm64-v8a全部都有,但是不同目录下的SO个数都不一样。

    这样打出来的APK包,在安装的时候会让Android系统“很为难”,它搞不清到底该选择哪个SO来安装。有时可能会造成某个SO的漏安装,那么在APP运行的时候加载SO时就会出现异常了。

    解决方案:

    1、只保留lib下的一个目录足够(armeabi或armeabi-v7a保留一个),其他目录全部不用配置。

    2、如果想继续多配置几个CPU架构的lib目录,那就全部配置齐全。实际上有时候很难做到,特别是当需要使用三方库的SO的时候,往往并不那么容易找的齐全。由于全部打齐全会对APK的体积有增加,所以还是推荐第一种方案。

  • lib库目录下的SO不符合相应的CPU架构。

    同上面的问题差不多,有些APK包打出来,同时配置了armeabi和arm64-v8,但是却在arm64-v8放置了某个或多个armeabi版本的SO,那么在APP运行的时候就会报类似的错误:"lib_xyz.so" is 32-bit instead of 64-bit

  • 64-bit下使用System.load加载SO:"lib_xyz.so" is 32-bit instead of 64-bit

    Use 32-bit jni libraries on 64-bit android - Stack Overflow

Found an explanation: 64-bit Android can use 32-bit native libraries as a fallback,
only if System.loadlLibrary() can't find anything better in the default search path.
You get an UnsatisfiedLinkError if you force the system to load the 32-bit library using System.load() with the full library path.
So the first workaround is using System.loadLibrary() instead of System.load().

64-bit处理器可以向下兼容32-bit指令集,即可以运行32-bit动态库,所以APK包仍然可以只保留lib下的一个目录足够(armeabi或armeabi-v7a保留一个),其他目录全部不用配置。

有一种组合错误,就是APK的lib库打的参差不齐,又在64-bit下使用System.load加载SO。

有一个APP在MX5(android5.0.1)下出现了以下异常:

    Caused by: java.lang.UnsatisfiedLinkError: dlopen failed: "/data/data/com.xxx.pris/app_lib/libPDEEngine.so" is 32-bit instead of 64-bit

首先可以大致知道这是一个64位的机器,查看云捕展示的机器信息,确实是arm64-v8a。首先就是看APK的lib目录打的对不对,果然

armeabi下有12个SO,而armeabi-v7a下却只有11个SO。但是他们使用了云捕代码来尝试安全加载SO来降低UnsatisfiedLinkError的异常。

        public static void loadLibrary(final Context context, final String library) {
if (context == null) {
throw new IllegalArgumentException("Given context is null");
} if (TextUtils.isEmpty(library)) {
throw new IllegalArgumentException("Given library is either null or empty");
} try {
System.loadLibrary(library);
return; } catch (final UnsatisfiedLinkError ignored) {
// :-(
CrashHandler.leaveBreadcrumb("ReLinker: System.loadLibrary failed");
} final File workaroundFile = getWorkaroundLibFile(context, library);
if (!workaroundFile.exists()) {
unpackLibrary(context, library);
} System.load(workaroundFile.getAbsolutePath());
}

可以看出,如果因为SO打的参差不齐导致了APK在安装的时候SO就已经有遗漏的没有被安装进lib的加载目录。那么System.loadLibrary的时候便会有异常,然后代码尝试解压并释放所需要的SO文件,但是这个时候只能通过System.load来加载了,又由于当前是arm64-v8a的机器,所以就出现了Use 32-bit jni libraries on 64-bit android - Stack Overflow的问题。

解决办法:

  1. APK包打的时候把SO打的齐全了,并建议只保留一个目录足够(armeabi或armeabi-v7a保留一个)。
  2. 云捕SDK在发现上述问题之后,尝试解压释放SO的时候,把解压目录设置到lib的加载路径顺序里去,并继续使用System.loadLibrary来加载(而不是System.load)。并在第一次System.loadLibrary出现异常时,面包屑告诉足够多的信息,例如是否是SO不存在。
  • java代码混淆导致。

由于Native层需要注册到java层函数,如果java层对应的类名和函数名在打包的时候被混淆了,肯定是会出现异常的。此类问题比较定位解决,但是也比较容易忘记。解决办法就是在proguard混淆时keep掉对应的类和函数。

  • 注册方式不对,或已经被其他类注册。

    早期的崩溃捕获功能是在加壳里用的,后来把崩溃捕获的代码单独抽出为云捕SDK,为了保证复用,加壳和云捕SDK共同使用一个libbugrpt.so。外壳如果注册了,则云捕不再注册。如果外壳已经注册过了,云捕仍然要继续注册使用,就会出现上面的错误。解决办法是:当外壳已经注册启用了崩溃捕获,则云捕不再启动。

  • empty/missing DT_HASH in "libxxxx.so" (built with --hash-style=gnu?)

    java.lang.UnsatisfiedLinkError: dlopen failed: empty/missing DT_HASH in "libxxxx.so" (built with --hash-style=gnu?)
    at java.lang.Runtime.loadLibrary(Runtime.java:371)
    at java.lang.System.loadLibrary(System.java:989)

    c++ - Android NDK UnsatisfiedLinkError: "dlopen failed: empty/missing DT_HASH" - Stack Overflow

总结

如果问题出现时可以尝试通过以上的几种方法来排查,如果有其他没有罗列的情形可以发给我,我将会持续收集整理并更新,以期帮助更多的开发者解决问题。

如果想要规避以上的问题,最好的办法就是打好打全相应CPU架构的SO文件。

另外你也可以直接使用云捕SDKRelinker.loadLibrary功能,来帮助你安全加载SO以降低此类UnsatisfiedLinkError的异常。

参考

[持续更新]UnsatisfiedLinkError常见问题及解决方案的更多相关文章

  1. 关于ASP.NET MVC开发设计中出现的问题与解决方案汇总 【持续更新】

    最近一直用ASP.NET MVC 4.0 +LINQ TO SQL来开发设计公司内部多个业务系统网站,在这其中发现了一些问题,也花了不少时间来查找相关资料或请教高人,最终都还算解决了,现在我将这些问题 ...

  2. HBase常见问题答疑解惑【持续更新中】

    HBase常见问题答疑解惑[持续更新中] 本文对HBase开发及使用过程中遇到过的常见问题进行梳理总结,希望能解答新加入的HBaser们的一些疑惑. 1. HTable线程安全吗? HTable不是线 ...

  3. webpack1.x环境配置与打包基础【附带各种 "坑" 与解决方案!持续更新中...】

    首先介绍传统模块化开发的主流方案: 1.基与CMD的sea.js,玉伯提出的解决方案,据说原来京东团队在使用.用时才定义,就近加载. 2.基于AMD的require.js,之前在用.提前声明与定义.国 ...

  4. BAT 前端开发面经 —— 吐血总结 前端相关片段整理——持续更新 前端基础精简总结 Web Storage You don't know js

    BAT 前端开发面经 —— 吐血总结   目录 1. Tencent 2. 阿里 3. 百度 更好阅读,请移步这里 聊之前 最近暑期实习招聘已经开始,个人目前参加了阿里的内推及腾讯和百度的实习生招聘, ...

  5. 消息队列面试题、RabbitMQ面试题、Kafka面试题、RocketMQ面试题 (史上最全、持续更新、吐血推荐)

    文章很长,建议收藏起来,慢慢读! 疯狂创客圈为小伙伴奉上以下珍贵的学习资源: 疯狂创客圈 经典图书 : <Netty Zookeeper Redis 高并发实战> 面试必备 + 大厂必备 ...

  6. java视频教程 Java自学视频整理(持续更新中...)

    视频教程,马士兵java视频教程,java视频 1.Java基础视频 <张孝祥JAVA视频教程>完整版[RMVB](东西网) 历经5年锤炼(史上最适合初学者入门的Java基础视频)(传智播 ...

  7. ( 译、持续更新 ) JavaScript 上分小技巧(四)

    后续如有内容,本篇将会照常更新并排满15个知识点,以下是其他几篇译文的地址: 第一篇地址:( 译.持续更新 ) JavaScript 上分小技巧(一) 第二篇地址:( 译.持续更新 ) JavaScr ...

  8. ( 译、持续更新 ) JavaScript 上分小技巧(三)

    最近家里杂事较多,自学时间实在少的可怜,所以都在空闲时间看看老外写的内容,学习之外顺便翻译分享~等学习的时间充足些再写写自己的一些学习内容和知识点分析(最近有在接触的:复习(C#,SQL).(学习)T ...

  9. 系列文章:老项目的#iPhone6与iPhone6Plus适配#(持续更新中,更新日期2014年10月12日 星期日 )

    本文永久地址为http://www.cnblogs.com/ChenYilong/p/4020399.html ,转载请注明出处. ********************************** ...

随机推荐

  1. php 3种常见设计模式

    1.工厂模式 <?php namespace Facebab; class Factory { static function createDatabase () { return new Da ...

  2. JPA 不在 persistence.xml 文件中配置每个Entity实体类的2种解决办法

    在Spring 集成 Hibernate 的JPA方式中,需要在persistence配置文件中定义每一个实体类,这样非常地不方便,远哥目前找到了2种方法.   这2种方式都可以实现不用persist ...

  3. ASP.NET MVC中实现多个按钮提交的几种方法

    有时候会遇到这种情况:在一个表单上需要多个按钮来完成不同的功能,比如一个简单的审批功能. 如果是用webform那不需要讨论,但asp.net mvc中一个表单只能提交到一个Action处理,相对比较 ...

  4. windows下clang的安装与使用

    我本意是想在windows下学习下C++11,而结果是我的Visual Studio 2012不完全支持,而我又懒得去安装2013/2015,太大了.公司运维也不允许我去下载- -,然后就想能不能在w ...

  5. InstallShield 2012 Spring优惠升级到最新版本(2015.4.30之前)

    InstallShield 2012 Spring即将EOF,所以仍在使用InstallShield 2012 Spring的用户请注意下面内容: InstallShield 2012 Spring升 ...

  6. js Array 交集 并集 差集 去重

    最劲项目需要用到js数组去重和交集的一些运算,我的数组元素个数可能到达1000以上,网上的实现方式都是2次循环,性能不适合我的需求,1000*1000那循环次数太多了,所以我这里采用对象object来 ...

  7. asp.net mvc 动态显示不同的部分视图

    首先是AJAX请求 //第一次打开 默认s单行文本 $.ajax({ type: "GET", url: "/Admin/Field/ChoiceType4Edit&qu ...

  8. ubuntu16.04+opencv3.1配置

    #安装必要的依赖sudo apt-get install build-essential cmakesudo apt-get install cmake Git libgtk2.0-dev pkg-c ...

  9. [GraphQL] Serve a GraphQL Schema as Middleware in Express

    If we have a GraphQL Schema expressed in terms of JavaScript, then we have a convenient package avai ...

  10. StringUtilsd的isEmpty、isNotEmpty、isBlank、isNotBlank

    1. public static boolean isEmpty(String str) 判断某字符串是否为空,为空的标准是 str==null 或 str.length()==0 下面是 Strin ...