我正在参与「启航计划」

故事的最初

我担任的项目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.PathClassLoadercouldn'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.solibcyberplayer.so仿制一份到该文件夹。假如这个不行,那么新建一个armeabi文件夹再放入libcyberplayer-core.solibcyberplayer.so就能够了。

3.在src/main/里仿制一份so文件:
src/main/里创立一个jniLibs文件夹,然后再建一个armeabi-v7a文件夹,最终把libcyberplayer-core.solibcyberplayer.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,是怎么运转在各种处理器的手机上的?
www.zhihu.com/question/36…

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>-xlib和安装包里证实了一下:
项目A中的lib/arm64/里是空的,所以没有报错。
项目B中的lib/arm64/里有libpl-droidsonroids_gif.solibpl-droidsonroids_gif_surface.so两个文件。

也就是说,因为运用的某个第三方库里编译了arm64的so库,导致没有编译相应arm64的库无法正常运用了。

其时想的处理计划是自己编译Baidu-T5Player-SDK-Android-1.4sarm64的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 播映器 SDK 开发攻略
  • Android项目开发填坑记-so文件引发的血案

假如有什么主张或者问题能够随时联系我,共同讨论学习:

  • Github: likfe
  • CSDN:他叫自己Mr.张
  • :cafeting
  • 微博:cafeting