【错误记录】NDK 报错 java.lang.UnsatisfiedLinkError 的一种处理方案 ( 主应用与依赖库 Module 的 CPU 架构配置不匹配导致 )
文章目錄
- 一、問(wèn)題描述
- 二、問(wèn)題排查
- 三、解決方案
一、問(wèn)題描述
NDK 開(kāi)發(fā) , 在調(diào)用 JNI 對(duì)應(yīng) Java 類(lèi)時(shí) , 靜態(tài)代碼塊中 System.loadLibrary 語(yǔ)句調(diào)用時(shí) , 報(bào)如下錯(cuò)誤 ;
static {System.loadLibrary("openssl");} 2020-12-01 10:35:48.993 20837-20837/? E/AndroidRuntime: FATAL EXCEPTION: mainProcess: kim.hsl.dex, PID: 20837java.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)二、問(wèn)題排查
出現(xiàn)上述錯(cuò)誤 , 就是 打包的 so 動(dòng)態(tài)庫(kù)沒(méi)有找到 , 有很多問(wèn)題都會(huì)導(dǎo)致該錯(cuò)誤 , 如 build.gradle 中沒(méi)有配置對(duì)應(yīng)的 CPU 架構(gòu) , NDK 中調(diào)用的外部動(dòng)態(tài)或靜態(tài)依賴(lài)庫(kù)的 CPU 架構(gòu)不匹配 ;
這里我遇到的問(wèn)題是 主應(yīng)用 與 依賴(lài)庫(kù)的 CPU 架構(gòu)不匹配導(dǎo)致 ;
創(chuàng)建項(xiàng)目時(shí)選擇如下選項(xiàng) , 自動(dòng)生成的 build.gradle 中默認(rèn)生成 arm64-v8a, armeabi-v7a, x86, x86_64 四種 CPU 架構(gòu)的動(dòng)態(tài)庫(kù) , 這就比較坑 , 一般開(kāi)發(fā)時(shí)只編譯 armeabi-v7a 這一種 CPU 架構(gòu)的動(dòng)態(tài)庫(kù) ;
在主應(yīng)用中 , 選擇了 C++ 支持 , 系統(tǒng)自動(dòng)生成的配置如下 :
plugins {id 'com.android.application'id 'kotlin-android' }android {compileSdkVersion 29buildToolsVersion "30.0.2"defaultConfig {applicationId "kim.hsl.myapplication"minSdkVersion 18targetSdkVersion 29versionCode 1versionName "1.0"testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"externalNativeBuild {cmake {cppFlags ""}}}buildTypes {release {minifyEnabled falseproguardFiles 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_8targetCompatibility 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' }上述 android / defaultConfig / externalNativeBuild / cmake / abiFilters 配置中沒(méi)有配置 CPU 架構(gòu) , 沒(méi)有配置 abiFilters CPU 架構(gòu)選項(xiàng) , 因此默認(rèn)生成 arm64-v8a, armeabi-v7a, x86, x86_64 四種 CPU 架構(gòu)的動(dòng)態(tài)庫(kù) ;
下圖是主應(yīng)用生成的 so 動(dòng)態(tài)庫(kù) :
可以明顯看到 主應(yīng)用的依賴(lài)庫(kù)生成了 四種 CPU 架構(gòu)的動(dòng)態(tài)庫(kù) , 我們使用的 libopenssl.so 動(dòng)態(tài)庫(kù)只有 armeabi-v7a 架構(gòu)的 , 當(dāng)在 arm64-v8a 架構(gòu)的手機(jī)中調(diào)用 OpenSSL 所在的類(lèi)時(shí) , 在 static 靜態(tài)代碼塊中的 System.loadLibrary 調(diào)用時(shí)就會(huì)報(bào)錯(cuò) ;
該應(yīng)用生成了 arm64-v8a 架構(gòu)的動(dòng)態(tài)庫(kù) , 但是生成的不全 , 導(dǎo)致上述問(wèn)題 , 解決方案是干脆不生成 arm64-v8a 架構(gòu)的動(dòng)態(tài)庫(kù) , 只生成 armeabi-v7a 架構(gòu)動(dòng)態(tài)庫(kù) , arm64-v8a 架構(gòu)的手機(jī)會(huì)向下兼容 armeabi-v7a 架構(gòu)動(dòng)態(tài)庫(kù) , 因此只編譯生成 armeabi-v7a 架構(gòu)動(dòng)態(tài)庫(kù)即可 ;
在另一個(gè)主應(yīng)用的 Android Library 中 , 其也使用了 NDK , 并且使用了外部依賴(lài)庫(kù) OpenSSL 靜態(tài)庫(kù) , 在 Ubuntu 中只交叉編譯了 armeabi-v7a 架構(gòu)的靜態(tài)庫(kù) , 因此不能生成 arm64-v8a 的動(dòng)態(tài)庫(kù) ;
下圖是依賴(lài)庫(kù)生成的 so 動(dòng)態(tài)庫(kù) :
目前的主流手機(jī)都是 arm64-v8a 或 armeabi-v7a 手機(jī) , x86 和 x86_64 手機(jī)很少 , 一般不進(jìn)行匹配 ;
一般的高端機(jī)型都是 arm64-v8a 架構(gòu)的 , 幾年前的機(jī)型可能是 armeabi-v7a 架構(gòu)的 ;
arm64-v8a 架構(gòu)的手機(jī) 可以兼容使用 armeabi-v7a 架構(gòu)的動(dòng)態(tài)庫(kù) ;
不過(guò)要注意一點(diǎn) , 前提是沒(méi)有配置 arm64-v8a 架構(gòu) , 如果配置了 arm64-v8a 架構(gòu) , 但是沒(méi)有對(duì)應(yīng) so 庫(kù) , 那就會(huì)出現(xiàn)上述錯(cuò)誤 ;
三、解決方案
解決方案 : 全部配置 armeabi-v7a 架構(gòu) , 這樣在所有的手機(jī)中只存在 armeabi-v7a 架構(gòu) 的動(dòng)態(tài)庫(kù) , 系統(tǒng)查找時(shí) , 就不會(huì)查找
android / defaultConfig / externalNativeBuild / cmake / abiFilters 配置 abiFilters 'armeabi-v7a' 即可 ;
plugins {id 'com.android.application'id 'kotlin-android' }android {compileSdkVersion 29buildToolsVersion "30.0.2"defaultConfig {applicationId "kim.hsl.myapplication"minSdkVersion 18targetSdkVersion 29versionCode 1versionName "1.0"testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"externalNativeBuild {cmake {cppFlags ""abiFilters 'armeabi-v7a'}}}buildTypes {release {minifyEnabled falseproguardFiles 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_8targetCompatibility 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' }主應(yīng)用中生成的 動(dòng)態(tài)庫(kù) , 只剩成了 armeabi-v7a 架構(gòu)的動(dòng)態(tài)庫(kù) ;
依賴(lài)庫(kù)中還是生成的 armeabi-v7a 架構(gòu)的動(dòng)態(tài)庫(kù) ;
問(wèn)題解決 ;
如果非要配置 arm64-v8a 架構(gòu) , 但是一旦配置上 , 所有的在 NDK 中使用到的依賴(lài)庫(kù) 如 OpenSSL , FFMPEG , RTMP , FAAC , OpenCV 等 , 都必須一式兩份 , 一份 armeabi-v7a 架構(gòu)的靜態(tài)/動(dòng)態(tài) 依賴(lài)庫(kù) , 一份 arm64-v8a 架構(gòu)的 靜態(tài) / 動(dòng)態(tài) 依賴(lài)庫(kù) ; ( 很麻煩 , APK 編譯后也很大 , 不推薦 )
總結(jié)
以上是生活随笔為你收集整理的【错误记录】NDK 报错 java.lang.UnsatisfiedLinkError 的一种处理方案 ( 主应用与依赖库 Module 的 CPU 架构配置不匹配导致 )的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 【Android 安全】DEX 加密 (
- 下一篇: 【Android 安全】DEX 加密 (