安卓如何完美的加载so库
android系统加载so一般有2种方式
system.loadlibrary
由给定的库名参数加载对应的本地库。库名参数不能包含任何平台相关的前缀、文件扩展符或路径。
正常情况下,都是这种方法加载。
1 | static { |
system.load
根据传入的文件名参数,加载此本地库。文件名必须是一个绝对路径。
这种方式适用于动态加载So,比如一些壳子的做法,将so放在assert目录下,动态加载so。
因为传递的都是一个绝对路径。
1 | static { |
System.getProperty(“java.library.path”)的值即是系统库的默认路径,loadLibrary方法会主动到此路径下
查找对应的库文件。
System.load()方法和System.loadLibrary的另一个区别就是,在处理库之间的依赖关系时。
假定现在有俩个库:A.dll 和 B.dll 并且A.dll依赖于B.dll,如果使用System.load(“D:/A.dll”)的话,
即使B.dll和A.dll位于同一个目录下,也会抛出异常。在这种情形下,JVM知道A.dll依赖于B.dll的话,它就会尝试着
在java.library.path下查找B.dll,如果找不到B.dll就会报错。
在这种情况下,有俩种解决方案:
- 先调用System.load(“D:/B.dll”),再调用System.load(“D:/A.dll”)
- 把A.dll和B.dll 都放在java.library.path下面,之后,再调用System.loadLibrary(“A”)就可以了。
Relinker
https://github.com/KeepSafe/ReLinker
以上两种方法最底层走的都是同一个native方法。
然而对于开发者来说,我有时候仅仅只是想加载一个so文件,没必要这么复杂。
那么此时又2个开源库,soloader和relinker。
更推荐用relinker,因为是优先loadLibrary,失败再去load。双重保障
官网介绍很简单:
Simply replace a call to System.loadLibrary
like this:
1 | System.loadLibrary("mylibrary"); |
With a call to ReLinker.loadLibrary
like this:
1 | ReLinker.loadLibrary(context, "mylibrary"); |
还有加载成功与失败的回调
1 | ReLinker.loadLibrary(context, "mylibrary", new ReLinker.LoadListener() { |
安卓加载so原理分析:https://cloud.tencent.com/developer/article/1563054