文章目录
一、问题描述
二、问题排查
三、解决方案
一、问题描述
NDK 开发 , 在调用 JNI 对应 Java 类时 , 静态代码块中 System.loadLibrary 语句调用时 , 报如下错误 ;
static { System.loadLibrary("openssl"); }
2020-12-01 10:35:48.993 20837-20837/? E/AndroidRuntime: FATAL EXCEPTION: main
Process: kim.hsl.dex, PID: 20837 java.lang.UnsatisfiedLinkError: dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/kim.hsl.dex-WPNFatgeDiPkh3jHexDmDg==/base.apk"],nativeLibraryDirectories=[/data/app/kim.hsl.dex-WPNFatgeDiPkh3jHexDmDg==/lib/arm64, /data/app/kim.hsl.dex-WPNFatgeDiPkh3jHexDmDg==/base.apk!/lib/arm64-v8a, /system/lib64, /hw_product/lib64, /system/product/lib64]]] couldn't find "libopenssl.so" at java.lang.Runtime.loadLibrary0(Runtime.java:1067) at java.lang.Runtime.loadLibrary0(Runtime.java:1007) at java.lang.System.loadLibrary(System.java:1668) at kim.hsl.multipledex.OpenSSL.<clinit>(OpenSSL.java:13) at kim.hsl.multipledex.OpenSSL.getBytes(OpenSSL.java:30) at kim.hsl.multipledex.ProxyApplication.attachBaseContext(ProxyApplication.java:124) at android.app.Application.attach(Application.java:358) at android.app.Instrumentation.newApplication(Instrumentation.java:1168) at android.app.LoadedApk.makeApplication(LoadedApk.java:1382) at android.app.ActivityThread.handleBindApplication(ActivityThread.java:7341) at android.app.ActivityThread.access$2400(ActivityThread.java:251) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2280) at android.os.Handler.dispatchMessage(Handler.java:110) at android.os.Looper.loop(Looper.java:219) at android.app.ActivityThread.main(ActivityThread.java:8375) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:513) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1055)
二、问题排查
出现上述错误 , 就是 打包的 so 动态库没有找到 , 有很多问题都会导致该错误 , 如 build.gradle 中没有配置对应的 CPU 架构 , NDK 中调用的外部动态或静态依赖库的 CPU 架构不匹配 ;
这里我遇到的问题是 主应用 与 依赖库的 CPU 架构不匹配导致 ;
创建项目时选择如下选项 , 自动生成的 build.gradle 中默认生成 arm64-v8a, armeabi-v7a, x86, x86_64 四种 CPU 架构的动态库 , 这就比较坑 , 一般开发时只编译 armeabi-v7a 这一种 CPU 架构的动态库 ;
在主应用中 , 选择了 C++ 支持 , 系统自动生成的配置如下 :
plugins { id 'com.android.application' id 'kotlin-android' } android { compileSdkVersion 29 buildToolsVersion "30.0.2" defaultConfig { applicationId "kim.hsl.myapplication" minSdkVersion 18 targetSdkVersion 29 versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" externalNativeBuild { cmake { cppFlags "" } } } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } externalNativeBuild { cmake { path "src/main/cpp/CMakeLists.txt" version "3.10.2" } } compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } kotlinOptions { jvmTarget = '1.8' } } dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" implementation 'androidx.core:core-ktx:1.3.2' implementation 'androidx.appcompat:appcompat:1.2.0' implementation 'com.google.android.material:material:1.2.1' implementation 'androidx.constraintlayout:constraintlayout:2.0.4' testImplementation 'junit:junit:4.+' androidTestImplementation 'androidx.test.ext:junit:1.1.2' androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' }
56
上述 android / defaultConfig / externalNativeBuild / cmake / abiFilters 配置中没有配置 CPU 架构 , 没有配置 abiFilters CPU 架构选项 , 因此默认生成 arm64-v8a, armeabi-v7a, x86, x86_64 四种 CPU 架构的动态库 ;
下图是主应用生成的 so 动态库 :
可以明显看到 主应用的依赖库生成了 四种 CPU 架构的动态库 , 我们使用的 libopenssl.so 动态库只有 armeabi-v7a 架构的 , 当在 arm64-v8a 架构的手机中调用 OpenSSL 所在的类时 , 在 static 静态代码块中的 System.loadLibrary 调用时就会报错 ;
该应用生成了 arm64-v8a 架构的动态库 , 但是生成的不全 , 导致上述问题 , 解决方案是干脆不生成 arm64-v8a 架构的动态库 , 只生成 armeabi-v7a 架构动态库 , arm64-v8a 架构的手机会向下兼容 armeabi-v7a 架构动态库 , 因此只编译生成 armeabi-v7a 架构动态库即可 ;
在另一个主应用的 Android Library 中 , 其也使用了 NDK , 并且使用了外部依赖库 OpenSSL 静态库 , 在 Ubuntu 中只交叉编译了 armeabi-v7a 架构的静态库 , 因此不能生成 arm64-v8a 的动态库 ;
下图是依赖库生成的 so 动态库 :
目前的主流手机都是 arm64-v8a 或 armeabi-v7a 手机 , x86 和 x86_64 手机很少 , 一般不进行匹配 ;
一般的高端机型都是 arm64-v8a 架构的 , 几年前的机型可能是 armeabi-v7a 架构的 ;
arm64-v8a 架构的手机 可以兼容使用 armeabi-v7a 架构的动态库 ;
不过要注意一点 , 前提是没有配置 arm64-v8a 架构 , 如果配置了 arm64-v8a 架构 , 但是没有对应 so 库 , 那就会出现上述错误 ;