Android开发笔记-通过DexClassLoader加载调用了JNI的类

公司项目需要将一个Android项目打包成apk文件并加密,然后在另一个Android项目中解密并动态加载。
一般情况下,我们调用System.loadLibrary("libraryName");就能加载so库,但是当我的子项目加载so库时报错了:

java.lang.UnsatisfiedLinkError: dalvik.system.DexClassLoader[
DexPathList[[zip file "/data/app/packageName/xxx/xxx.apk"],
nativeLibraryDirectories=[/vendor/lib, /system/lib]]] 
couldn't find "libraryName.so"

也就是找不到so库文件,项目是使用DexClassLoader加载的,一开始尝试了把库文件放到子项目里面,发现行不通,apk文件里面虽然打包了so文件,但是加载的时候so文件还是在apk文件里面,需要用某种方式将so文件从apk文件里面提取出来才行。
后来又尝试了把so库文件放到主项目中,并提前在加载子项目之前执行System.loadLibrary("libraryName");
发现这样也不行,子项目不能直接使用主项目加载的库。
后来看了下DexClassLoader的构造函数是这样的:

public DexClassLoader(String dexPath, String optimizedDirectory,
String librarySearchPath, ClassLoader parent);

其中可以自定义librarySearchPath,也就是不用在系统目录中去找库文件。
接下来思路就清晰了,就是要找到app安装在手机里后,so文件的路径。
于是通过百度、google,找到了获取库路径的语句:

getApplicationInfo().nativeLibraryDir

但是这种方式依然不行,子项目依然无法加载到so库,也就是说库文件不在这个目录,而且这条语句获取到的目录路径是/data/app/packageName/lib/arm,而我使用的库的cpu架构是armeabi-v7a,所以这个目录路径不正确。
然后我在主项目中加载一个不存在的库,此时提示

java.lang.UnsatisfiedLinkError: dalvik.system.PathClassLoader[DexPathList[[
zip file "/data/app/packageName-1/base.apk"],
nativeLibraryDirectories=[/data/app/packageName-1/lib/arm, 
/data/app/packageName-1/base.apk!/lib/armeabi-v7a, /vendor/lib, /system/lib]]] 
couldn't find "libraryName.so"

这样就知道了主项目加载库文件的路径,于是我把librarySearchPath改成了这个路径,编译运行。
结果又报错了:

java.lang.UnsatisfiedLinkError: dalvik.system.PathClassLoader[DexPathList[[
zip file "/data/app/packageName-2/base.apk"],
nativeLibraryDirectories=[/data/app/packageName-2/lib/arm, 
/data/app/packageName-2/base.apk!/lib/armeabi-v7a, /vendor/lib, /system/lib]]] 
couldn't find "libraryName.so"

packageName后面的1和2还是会变化的,也就是这可能是个临时生成的路径,我还是要动态获取库目录的路径才行。
通过在网上搜索资料,知道了ClassLoader里有个findLibrary(String libname)函数可以获取库文件的路径,但是ClassLoader下的这个函数是protected的,类外包外不可见,不能直接调用,不过BaseDexClassLoader继承了ClassLoader,并且它的findLibrary(String name)是public的,我们可以通过调用它来获取库文件路径。
这个函数获取的是某个具体的库文件的路径,截取出库目录路径即可。
最后的代码如下:

String librarySearchPath = ((BaseDexClassLoader) getClassLoader()).findLibrary("libraryName");
librarySearchPath = librarySearchPath.substring(0, librarySearchPath.lastIndexOf('/'));
DexClassLoader classLoader = new DexClassLoader(dexPath,optimizedDirectory,
        librarySearchPath, getClassLoader());

这个问题也许有更好的解决办法,不过目前只想到这种,以后找到更好的再更新。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值