原文地址:http://www.cnblogs.com/linguanh/ (滑至文章末,直接看解决方法)
问题起因:
前5天,因为项目里面有个类似 仿微信 视频录制的功能, 先是上网找了个 开源项目:https://github.com/qdrzwd/VideoRecorder,下载下来,在 debug 非混淆的模式下 测试了几次,觉得效果还不错,便在它的基础上进行了 二次开发。
于当天晚上整合好项目,准备第一次的混淆打包(release模式),然后第一次测试,结果,我意料中的事情发生了,没错,就是在混淆后经常发生的各种 蹦,对于这类问题,不吹不黑,我经验算是丰富的了,一般都是在 proguard-rules 文件(android studio) 下做混淆设置解决的,但我不得不承认,这个是我迄今遇到最棘手的,直到 15:46 才正式解决,怎么说都 4 天了,百度上没有直接的解决信息,逐择文以告之。
前序:
先说说这个开源项目的背景吧,它是基于 Vine 的背景下进行开发的,Vine 是外国的一个做短视频分享起家的公司,也是他们 APP 的名字,后被Twitter收购,目前网上的录制视频都是基于android自带的MediaRecorder类,但是这个类比较鸡肋,实话实说,用处不是很大,用来练习下还是可以的。Vine 录制视频使用javacv自带的api, 录制声音使用的是android的AudioRecord,同样,这个开源项目也是基于 二者 开发的。这里顺便说下,微信用的库,微信和微视一样,用的是自己编译的 ffmpeg库,vine使用的是javacv库。看到这里,你是不是在想,我是怎么知道的?其实很简单,去网上下载这几个 APP,反编译下,看看 libs 下的 .so 就知道了。
网上查资料后发现javacv已经提供了视频录制功能,并且包含有视频编辑等图像处理功能。在javacv的开源项目链接可以下载它:https://code.google.com/p/javacv/
具体问题:
好了,前面吹了这么多,先说下我遇到的奇葩问题先。
从下往上看,到最后提示的是 加载动态链接库 libjniPointer.so 出问题了,这是一处比较重要的信息,还有两处分别是 javacpp.loader.loadLibrary 、 nativeLibraryDirectories=[/data/app/cn.itguy.recordvideodemo-1/lib/arm, /vendor/lib, /system/lib]] ,它们告诉了我三点, 这个问题是加载 linux 下的动态库失败,找不到了,由jar包里面的loader类中的loadLibrary函数触发,最终找不到的位置是手机系统的的lib库,system、vendor。
是不是有种想去手机system/lib 里面看看有没有 jniPointer.so 的冲动?事实不用去看,我前面说过在 debug 下是没问题的,也就证明了这个库必然存在,找不到是因为混淆的原因。
通常的做法:
因为这类问题是库找不到,一般我们回去自己项目里面的 .so 文件夹中找找有木有,这是一种盲目的做法,首先应该看错误信息,例如上面的,找不到的路径的 system/lib 也就和本地项目文件夹无关,事实也是这样,libjniPointer.so 这个东东,原来项目里面就是没有的。
然后就是混淆配置文件--proguard-rules:具体的所有操作,网上有很详细的例子,我这里不废话,直接针对我遇到的情况开刀
首先点开用到的jar包 为了保证 里面的包不被混编,我们会使用 -keep 和 -dontwarn,然后再补上一句不混淆 native方法->,依赖注入不混淆->,还不放心的话,可以狠点再次指出属性和方法都不混淆->,看到这里,我们会想,应该行了,一般是行的,可能有同志会指出要保护下 .so 啊,-libraryjars libs/xxx.so 这样子,其实不用,.so 默认不混淆的,所有上面的做法,一般来说,是行的,但是,对于这个视频录制来说,还不行。
真正解决:
在执行了上面的设置后,如果还不行的话,基本上再百度也没什么用了,因为百度上面没有,等我发完这篇文章估计就有了。
再回到问题的根源, 它是加载由jar包里面的loader类中的loadLibrary函数触发,最终找不到的位置是手机系统的的lib库,system、vendor 下的jniPointer.so,我们怎么办啊?看源码,还是得这样的,下面我贴出我的查找路径,所有代码是 这个 视频录制 开源项目、javacpp 里面的:
首先打 log 跟踪到->,在new AVPacket() 里面抛出异常,我们点进去->,因为allocate()没有其他操作,我们可以跳过它,在此类里查找 static 静态块,它先于构造函数执行->->->->,看到loadLibrary了-> 最终getRunTime,整条线索对应 异常信息,到了这里,这里是系统的 system 类,当 libName = “libjnipointer” 的时候,找不到了。 推测,是系统的某些资源被混淆了。我们的混淆配置中有一句设置:-keepattributes 保护给定的可选属性,那么我们可以用它保护下项目的注释、资源文件、资源目录名、内部类等,例如这样:,事实证明,当我添加到 InnerClasses 的时候,问题解决。
解决方法:
在混淆文件中添加 保护下项目的注释、资源文件、资源目录名、内部类(主要的解决项)