非常多朋友在开发Android JNI的的时候,会遇到findlibrary returned null的错误,由于某种原因,so没有打包到apk中。以下浅析下引起该错误的原因以及平台兼容性问题。
Android设备载入so怎样选择
眼下主流的Android设备肯定是armeabi-v7a架构的,然后就是x86和armeabi了。那么Android设备在执行程序时怎样选择载入包中的哪个so呢?
x86设备肯定优先寻找x86目录下的so。armeabi-v7a架构的设备肯定优先选择寻找项目中armeabi-v7a目录下的so。那假设项目中没有相应的目录和so呢?
我们以x86设备为例,x86设备会在项目中的 libs目录寻找是否含有x86目录,假设含有x86目录,则默觉得该项目有x86相应的so可执行的,仅仅有x86目录而目录下没有so。程序执行也是会出现findlibrary returned null的错误的。假设project本身不含有x86目录,则会寻找armeabi或者armeabi-v7a目录,兼容执行。 以armeabi-v7a设备为例(如今大多数设备都是armeabi-v7a架构的)。该Android设备当然优先寻找libs目录下的armeabi-v7a目录,相同,假设仅仅有armeabi-v7a目录而没有 so也是会报错的。假设找不到armeabi-v7a目录,则寻找armeabi目录。兼容执行该目录下的so,可是不能兼容执行x86的so。所以项目中假设仅仅含有x86的so。在armeabi和armeabi-v7a也是无法执行的。 以上就是不同CPU架构执行时载入so的策略。
没有将so打包到apk中的原因。
当你发现到findlibrary returned null的错误时。根本原因是so没有放到相应的目录中去,事实上最直接的解决的方法就是解压apk,看看apk中的x86、armeabi、armeabi-v7a目录中是否有相应的so。此时你可能在相应的目录下发现少了so,然后再去查原因就可以。
一般有双方面的原因:
1.apk中有相应平台的目录,可是目录里却没有相应的so。
举个样例,apk中lib以下一旦出现x86目录,程序执行的时候就会去载入x86相应的库,可是假设此时x86目录没有将so放进来,则会遇到报错。
2.第三方对平台的兼容策略与自己不一致。
可能第三方选择了仅仅支持armeabi(如果某支付sdk)。可是我们的游戏在Application.mk中配置了APP_ABI := all,如此,我们的游戏打包出 了全部平台的so,可是第三方却仅仅有armeabi目录相应的so,造成程序执行异常,这样的情况在开发期间最常见,一些小公司因为測试人员不足或者測试设备不足,上线后才发现这个问题也不奇怪。
对于平台的支持,我们应该怎样选择。
armeabi-v7a确实是能够兼容armeabi的。而v7a的CPU支持硬件浮点运算,眼下绝大对数设备已经是v7a了,所以为了性能上的更优,就不要为了兼容放到armeabi。x86是能够兼容armeabi平台执行的,不管是armeabi-v7a还是armeabi。同一时候带来的也是性能上的损耗。另外须要指出的是,打包出的x86的so,总会比armeabi平台的体积更小,对于性能有洁癖的童鞋们。还是建议在打包so的时候支持x86。详细会有如何的性能损耗,作者还不能说的很清楚。能够訪问下intel官方在csdn的博客。
总结一下在项目中的表现就是: 假设项目仅仅包括了 armeabi,那么在全部Android设备都能够执行; 假设项目仅仅包括了 armeabi-v7a。除armeabi架构的设备外都能够执行; 假设项目仅仅包括了 x86,那么armeabi架构和armeabi-v7a的Android设备是无法执行的。 假设同一时候包括了 armeabi, armeabi-v7a和x86,全部设备都能够执行,程序在执行的时候去载入不同平台相应的so,这是较为完美的一种解决方式,同一时候也会导致包变大。