Android项目开发填坑记-so文件引发的攻坚战
2016-03-16 16:41
295 查看
故事的最初
我负责的项目A要求有播放在线视频的功能,当时从别人的聊天记录的一瞥中发现百度有相关的SDK,当时找到的是Baidu-T5Player-SDK-Android-1.4s,项目中Demo的
so库只有
armeabi-v7a版的,由于需要使用的时候拷贝一些界面和图片资源到现有的项目中,所以我就索性直接打包成了
aar,经过一番修改就上线了。
Bug出现的那晚
播放在线视频的功能应要求被保留到新的一个项目B中,由于从开始一直都没有相关的需求出来,也就没有测试,毕竟项目A一直也在迭代更新,视频播放功能也一直很正常。然后项目经理突发奇想(请允许我这样描述),要求我加上录视频和发视频的功能,我想这应该不难。很快录视频和上传搞定了,我欢喜的开始测试刚刚发布的视频,高潮来了:
点击视频播放,画面一闪而过(不敢相信):
//这里用<package-name>代表我的包名 W/System.err: java.lang.UnsatisfiedLinkError: dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/<package-name>-1/base.apk"],nativeLibraryDirectories=[/data/app/<package-name>-1/lib/arm64, /vendor/lib64, /system/lib64]]] couldn't find "libcyberplayer-core.so" W/System.err: at java.lang.Runtime.loadLibrary(Runtime.java:366) W/System.err: at java.lang.System.loadLibrary(System.java:988) W/System.err: at com.baidu.cyberplayer.core.CyberPlayerCore.a(SourceFile:288) W/System.err: at com.baidu.cyberplayer.core.CyberPlayer.<init>(SourceFile:389) W/System.err: at com.baidu.cyberplayer.core.b.<init>(SourceFile:169) W/System.err: at com.baidu.cyberplayer.core.BVideoView$1.handleMessage(SourceFile:594) W/System.err: at android.os.Handler.dispatchMessage(Handler.java:102) W/System.err: at android.os.Looper.loop(Looper.java:135) W/System.err: at android.app.ActivityThread.main(ActivityThread.java:5295) W/System.err: at java.lang.reflect.Method.invoke(Native Method) W/System.err: at java.lang.reflect.Method.invoke(Method.java:372) W/System.err: at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:910) W/System.err: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:705)
日志的意思是在项目的
lib/arm64里找不到
libcyberplayer-core.so文件了。
漫漫DeBug路
网上搜索了一会儿 能找到相关错误的信息不多:搜索关键字:
java.lang.UnsatisfiedLinkError: dalvik.system.PathClassLoader、
couldn't find "libcyberplayer-core.so"等等
尝试的解决方案:
1.在gradle里指定包含的so文件
android { ... packagingOptions { exclude "libs/armeabi-v7a/libcyberplayer.so" exclude "libs/armeabi-v7a/libcyberplayer-core.so" } }
2.在
libs里复制一份so文件:
在
libs下新建一个
armeabi-v7a,然后将
libcyberplayer-core.so和
libcyberplayer.so复制一份到该文件夹。如果这个不行,那么新建一个
armeabi文件夹再放入
libcyberplayer-core.so和
libcyberplayer.so就可以了。
3.在
src/main/里复制一份so文件:
在
src/main/里创建一个
jniLibs文件夹,然后再建一个
armeabi-v7a文件夹,最后把
libcyberplayer-core.so和
libcyberplayer.so复制一份到
armeabi-v7a文件夹中
其它的都类似就不一一举例了。在尝试的过程中我发现方案
2没任何作用,复制文件之后程序没有进行重新编译,但是方案
3会导致项目重新打包编译。
随着查的资料越来越多(三个小时),发现
arm64对应的文件夹是
arm64-v8a,既然方案
3起作用,那就结合一下试试:
src/main/jniLibs/ --armeabi-v7a/ ----libcyberplayer-core.so ----libcyberplayer.so --arm64-v8a/ ----libcyberplayer-core.so ----libcyberplayer.so
怀着期待的心情我再次运行了程序:
arm64/libcyberplayer-core.so is 32bit not 64bit
顿时我意识到这so库根本没有编译64bit的版本啊。
然而,为什么项目A就没有这样的问题呢?
然而,为什么项目A就没有这样的问题呢?
然而,为什么项目A就没有这样的问题呢?
解决Bug的突破点
在大约三个半小时的搜索和尝试之后,我搜索到一个知识点:安装包在只编译了armeabi,没有x86、arm64-v8a,是如何运行在各种处理器的手机上的?
https://www.zhihu.com/question/36893314/answer/69467752
arm64-v8a是可以向下兼容的,但前提是你的项目里面没有arm64-v8a的文件夹,如果你有两个文件夹armeabi和arm64-v8a,两个文件夹,armeabi里面有a.so 和 b.so,arm64-v8a里面只有a.so,那么arm64-v8a的手机在用到b的时候发现有arm64-v8a的文件夹,发现里面没有b.so,就报错了,所以这个时候删掉arm64-v8a文件夹,这个时候手机发现没有适配arm64-v8a,就会直接去找armeabi的so库,所以要么你别加arm64-v8a,要么armeabi里面有的so库,arm64-v8a里面也必须有
于是我使用ROOT之后的手机,去
/data/app/<package-name>-x的
lib和安装包里证实了一下:
项目A中的
lib/arm64/里是空的,所以没有报错。
项目B中的
lib/arm64/里有
libpl-droidsonroids_gif.so和
libpl-droidsonroids_gif_surface.so两个文件。
也就是说,因为使用的某个第三方库里编译了
arm64的so库,导致没有编译相应
arm64的库无法正常使用了。
当时想的解决方案是自己编译
Baidu-T5Player-SDK-Android-1.4s的
arm64的so文件,虽然想着官方可能会有更新的版本里已经编译了,不过没有找到(github和旧的百度开发文档1.4还是最新版),最后在百度开发者论坛里有人说
Baidu-T5Player-SDK-Android-1.10s版本快出了,最终在最新的百度云开发者中新下载了最新版1.13的sdk,里面的确有
arm64的so文件,问题终于解决了。
总结和提醒
so库是旧版本兼容高版本(低版本的可以在高版本没有的情况下正常运行),也就是后兼容,前提是高版本的文件夹为空。这里就要求我们在开发的过程中要特别注意使用的第三方库是否使用了
jni库,其编译了那些版本的so文件,一旦其中一个
arm64有so文件,就要求其他库也必须编译了
arm64的so文件。
一句话就是:要有大家都得有,否则都不能有。
整个Bug解决的过程,让我意识到,要多了解一下整个开发的相关基础知识点,就算现在还没用到,比如
Jni甚至
ndk的基础知识点。
相关文章推荐
- Android四大组件之Activity
- Android项目开发填坑记-so文件引发的攻坚战
- Android之自定义简单小框架
- android.view.WindowManager$BadTokenException: Unable to add window -- token android.os.BinderProxy@4
- Android---Volley请求天气接口JSON解析
- JNI签名-android
- Android基础-Android的生命周期
- 完成一个安卓小项目之后的小感悟
- Android 之SQLite(增 删 改 查)
- 总结开始学习Android至今(大概有一周)
- Android图片海报制作-MaterialDesign使用
- Android xmlns 的作用及其自定义
- 框架模式MVC 在Android中的使用
- Android,在LinearLayout中动态添加TextView,几点疑问
- android 资源(开源项目、library,框架{完善中})
- Android的进化史
- Robotium导入被测源码遇到问题 had used a different Landroid/support/v4/view/ViewPager
- 跟着Google学Android —— 0 积跬步 以至千里
- Android-Service
- Android基础_日期选择器DatePickerDialog时间选择器TimePickerDialog隐藏输入法