Flutter 应用加载动态库失败
Posted
技术标签:
【中文标题】Flutter 应用加载动态库失败【英文标题】:Failed to load dynamic library in Flutter app 【发布时间】:2021-04-09 13:57:04 【问题描述】:我在 Google Play 商店中有一个正在生产的 Flutter 应用程序,其中包括一个使用 NDK 构建并在运行时加载的本机动态库(我称之为 libraster.so
)。在大多数设备上,这个库都存在并且加载良好。但在某些设备上,以下ArgumentError
在运行时出现Invalid argument(s): Failed to load dynamic library (dlopen failed: library "libraster.so" not found)
。
我相信这些设备是 ARM 设备。该应用未在应用模块的build.gradle
文件中指定任何abiFilter
。
使用 Google Play 控制台的 App Bundle Explorer,我可以下载将分发到受影响设备的 APK,它们通常包含 libraster.so
。
根据我的错误日志,目前受影响的设备有:
Model | Name | android version |
---|---|---|
SM-G928F | Samsung Galaxy S6 Edge+ | 6.0.1 |
SM-J500M | Samsung Galaxy J5 | 6.0.1 |
SM-J710GN | Samsung Galaxy J7 2016 | 6.0.1 |
SM-T110 | Samsung Galaxy Tab 3 Lite 7.0 | 4.2.2 |
SM-T111M | Samsung Galaxy Tab 3 Lite 7.0 | 4.2.2 |
GT-I8262 | Samsung Galaxy Core Duos | 4.1.2 |
GT-I8552 | Samsung Galaxy Win Duos | 4.1.2 |
GT-I8552B | Samsung Galaxy Win Duos | 4.1.2 |
GT-I9082L | Samsung Galaxy Grand Duos | 4.2.2 |
GT-I9300 | Samsung Galaxy S III | 4.1.2 |
GT-N8000 | Samsung Galaxy Note 10.1 | 4.1.2 |
GT-N8010 | Samsung Galaxy Note 10.1 | 4.1.2 |
GT-P3110 | Samsung Galaxy Tab 2 7.0 | 4.1.2 |
GT-P5110 | Samsung Galaxy Tab 2 10.1 | 4.2.2 |
SO-03E | Sony Xperia Tablet Z | 4.1.2 |
B1-A71 | Acer Iconia Tab B1-A71 | 4.1.2 |
F-01F | Fujitsu Arrows NX F-01F | 4.2.2 |
ME173X | Asus Memo Pad HD7 | 4.2.2 |
主要是 Android 4.1.2、4.2.2 和 6.0.1 设备。
这是我的应用模块build.gradle
的简化版本:
apply plugin: 'com.android.application'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
android
compileSdkVersion 29
lintOptions
disable 'InvalidPackage'
defaultConfig
applicationId "com.example.package"
minSdkVersion 16
targetSdkVersion 29
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
multiDexEnabled true
externalNativeBuild
cmake
arguments "-DCOMPILE_TESTS:BOOL=OFF"
// Maintains debug symbols
packagingOptions
doNotStrip '**.so'
signingConfigs
release
keyAlias keystoreProperties['keyAlias']
keyPassword keystoreProperties['keyPassword']
storeFile file(keystoreProperties['storeFile'])
storePassword keystoreProperties['storePassword']
buildTypes
release
signingConfig signingConfigs.release
minifyEnabled true
useProguard true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
ndk
debugSymbolLevel = 'FULL'
externalNativeBuild
cmake
version "3.19.2"
path "path/to/CMakeLists.txt"
flutter
source '../..'
dependencies
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
implementation 'com.google.code.gson:gson:2.8.5'
implementation 'androidx.multidex:multidex:2.0.1'
apply plugin: 'com.google.gms.google-services'
还有proguard-rules.pro
:
#Flutter Wrapper
-keep class io.flutter.app.** *;
-keep class io.flutter.plugin.** *;
-keep class io.flutter.util.** *;
-keep class io.flutter.view.** *;
-keep class io.flutter.** *;
-keep class io.flutter.plugins.** *;
-dontwarn io.flutter.embedding.**
-keep class com.example.package.** *;
使用的 Flutter 版本稳定1.22.5
。
这是 Flutter 中的错误吗?这些设备加载动态库是否与其他设备不同? libraster.so
在某些场景下是不是真的没有和APK打包?
【问题讨论】:
【参考方案1】:此处报告了类似问题:https://github.com/simolus3/moor/issues/895
建议的解决方法是针对这种情况创建一个调用 System.loadLibrary() 的 Flutter 插件
【讨论】:
谢谢,是的,这是我最终采用的解决方案,正如 Dart 团队成员所建议的那样:github.com/flutter/flutter/issues/73318#issuecomment-754598119【参考方案2】:我知道这是一个老问题,但我最近遇到了这个问题,我通过在 pub spec.yaml 中添加 sqlite3_flutter_libs 作为依赖项解决了这个问题
dependencies:
moor: ^4.3.0
sqlite3_flutter_libs: ^0.4.2
【讨论】:
【参考方案3】:感谢knaeckeKami,这是一个解决方案。
首先,你需要创建一个插件:
package <your_package>
import android.content.Context
import android.content.pm.ApplicationInfo
import android.content.pm.PackageManager
import androidx.annotation.NonNull
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
import io.flutter.plugin.common.MethodChannel.Result
import io.flutter.plugin.common.PluginRegistry.Registrar
class Plugin: FlutterPlugin, MethodCallHandler
companion object
const val TAG = <YOUR_TAG>
private lateinit var channel: MethodChannel
private lateinit var context: Context
override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding)
context = flutterPluginBinding.applicationContext
channel = MethodChannel(flutterPluginBinding.binaryMessenger, <CHANNEL_NAME>)
channel.setMethodCallHandler(this)
override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result)
if (call.method == "getNativeLibraryDirectory")
val applicationInfo: ApplicationInfo = context.packageManager.getApplicationInfo(context.packageName, PackageManager.GET_META_DATA)
if (applicationInfo != null)
result.success(applicationInfo.nativeLibraryDir)
else
result.success(null)
else
result.notImplemented()
override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding)
channel.setMethodCallHandler(null)
那么您可以使用_getAndroidDynamicLibrary(String libraryName)
而不是DynamicLibrary.open(libraryName)
来加载您的库:
Future<DynamicLibrary> _getAndroidDynamicLibrary(String libraryName) async
try
return DynamicLibrary.open(libraryName);
catch (_)
try
final String? nativeLibraryDirectory = await _getNativeLibraryDirectory();
return DynamicLibrary.open('$nativeLibraryDirectory/$libraryName');
catch (_)
try
final PackageInfo packageInfo = await PackageInfo.fromPlatform();
final String packageName = packageInfo.packageName;
return DynamicLibrary.open('/data/data/$packageName/lib/$libraryName');
catch (_)
rethrow;
用法:
Future<DynamicLibrary> _getNativeAppTokenLibrary() async => Platform.isAndroid
? await _getAndroidDynamicLibrary(_libraryName)
: DynamicLibrary.process();
【讨论】:
以上是关于Flutter 应用加载动态库失败的主要内容,如果未能解决你的问题,请参考以下文章
无法加载动态库“libtensorflowlite_c.so”:dlopen 失败:找不到库“libtensorflowlite_c.so”
无法加载 DLL“rasapi32.dll”: 动态链接库(DLL)初始化例程失败。的处理备注方案