空安全迁移后Flutter应用Release模式因本地化启动崩溃
Flutter 3.3.4 Release模式启动崩溃(本地化相关)
完成空安全迁移并将Flutter SDK从2.8.0升级至3.3.4后,应用在Release模式下启动时崩溃:显示黑屏2秒后自动关闭。迁移前应用运行正常。
已确认问题出在本地化功能上——注释MaterialApp组件中的supportedLocales、localizationsDelegates和localeResolutionCallback参数后,启动页可正常显示。该问题在Android和iOS平台上表现一致。
Flutter Doctor检查结果
[✓] Flutter (Channel stable, 3.3.4, on macOS 12.6 21G115 darwin-x64, locale en-GB) • Flutter version 3.3.4 on channel stable at /Users/sissa/fvm/versions/3.3.4 • Upstream repository https://github.com/flutter/flutter.git • Framework revision eb6d86ee27 (9 days ago), 2022-10-04 22:31:45 -0700 • Engine revision c08d7d5efc • Dart version 2.18.2 • DevTools version 2.15.0 [✓] Android toolchain - develop for Android devices (Android SDK version 30.0.3) • Android SDK at /Users/sissa/Library/Android/sdk • Platform android-33, build-tools 30.0.3 • ANDROID_HOME = /Users/sissa/Library/Android/sdk • Java binary at: /Applications/Android Studio 3.app/Contents/jre/Contents/Home/bin/java • Java version OpenJDK Runtime Environment (build 11.0.13+0-b1751.21-8125866) • All Android licenses accepted. [✓] Xcode - develop for iOS and macOS (Xcode 14.0.1) • Xcode at /Applications/Xcode.app/Contents/Developer • Build 14A400 • CocoaPods version 1.11.3 [✓] Chrome - develop for the web • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome [✓] Android Studio (version 2021.3) • Android Studio at /Applications/Android Studio 3.app/Contents • Flutter plugin can be installed from: 🔨 https://plugins.jetbrains.com/plugin/9212-flutter • Dart plugin can be installed from: 🔨 https://plugins.jetbrains.com/plugin/6351-dart • Java version OpenJDK Runtime Environment (build 11.0.13+0-b1751.21-8125866) [✓] VS Code (version 1.40.0) • VS Code at /Applications/Visual Studio Code.app/Contents • Flutter extension can be installed from: 🔨 https://marketplace.visualstudio.com/items?itemName=Dart-Code.flutter [✓] Connected device (3 available) • PRA LX1 (mobile) • 9DC7N17707001642 • android-arm64 • Android 7.0 (API 24) • macOS (desktop) • macos • darwin-x64 • macOS 12.6 21G115 darwin-x64 • Chrome (web) • chrome • web-javascript • Google Chrome 106.0.5249.119 [✓] HTTP Host Availability • All required HTTP hosts are available • No issues found!
app.dart -> build方法
@override Widget build(BuildContext context) { return KeyedSubtree( key: key, child: provider.ChangeNotifierProvider<BluetoothConnectionProvider>.value( value: bluetoothConnectionProvider as BluetoothConnectionProvider, child: LiveCycleManager( child: MaterialApp( navigatorKey: NavigationService.navigatorKey, supportedLocales: [ Locale('en', 'GB'), Locale('es', 'ES'), Locale('fr', 'FR'), Locale('ca', 'CA'), Locale('it', 'IT'), Locale('de', 'DE'), Locale('en', 'ES'), Locale('fr', 'ES'), Locale('ca', 'ES'), Locale('it', 'ES'), Locale('de', 'ES'), ], localizationsDelegates: [ AppLocalizations.delegate, GlobalCupertinoLocalizations.delegate, GlobalMaterialLocalizations.delegate, GlobalWidgetsLocalizations.delegate, ], localeResolutionCallback: (deviceLocale, supportedLocales) { for (Locale locale in supportedLocales) { // if device language is supported by the app, // just return it to set it as current app language if (supportedLocales.contains(deviceLocale)) { locator<Resources>().prefs!.preferences!.setString( kCurrentLocaleLanguage, deviceLocale!.languageCode); return deviceLocale; } } // if device language is not supported by the app, // the app will set it to english but return this to set to Bahasa instead locator<Resources>() .prefs! .preferences! .setString(kCurrentLocaleLanguage, 'en'); return Locale('en', 'EN'); }, theme: getAppTheme(), routes: { SplashScreen.routeName: (context) => SplashScreen(), LoginScreen.routeName: (context) => LoginScreen(), ResetPasswordScreen.routeName: (context) => ResetPasswordScreen(), RegisterScreen.routeName: (context) => RegisterScreen(), // ..... }, home: FlavorBanner( child: SplashScreen(), flavor: widget.appConfig!.flavor, ), debugShowCheckedModeBanner: false), ), ), ); }
AppLocalizations.delegate
class AppLocalizations { final Locale locale; AppLocalizations(this.locale); // Helper method to keep the code in the widgets concise // Localizations are accessed using an InheritedWidget "of" syntax static AppLocalizations? of(BuildContext context) { return Localizations.of<AppLocalizations>(context, AppLocalizations); } // Static member to have a simple access to the delegate from the MaterialApp static const LocalizationsDelegate<AppLocalizations> delegate = _AppLocalizationsDelegate(); Map<String, String>? _localizedStrings; Future<bool> load() async { // Load the language JSON file from the "lang" folder printLog('LOCALE_SAMCLA:${locale.languageCode}'); String jsonString = await rootBundle.loadString('i18n/${locale.languageCode}.json'); Map<String, dynamic> jsonMap = json.decode(jsonString); _localizedStrings = jsonMap.map((key, value) { return MapEntry(key, value.toString()); }); return true; } // This method will be called from every widget which needs a localized text String? translate(String? key) { if (null == key) return _localizedStrings?['LOC_ACTION_COMPLETED_NOT_SUCCESSFULLY']; String? text = _localizedStrings?[key]; return text ?? _localizedStrings?['LOC_ACTION_COMPLETED_NOT_SUCCESSFULLY']; } } // LocalizationsDelegate is a factory for a set of localized resources // In this case, the localized strings will be gotten in an AppLocalizations object class _AppLocalizationsDelegate extends LocalizationsDelegate<AppLocalizations> { // This delegate instance will never change (it doesn't even have fields!) // It can provide a constant constructor. const _AppLocalizationsDelegate(); @override bool isSupported(Locale locale) { // Include all of your supported language codes here return ['en', 'ca', 'fr', 'es', 'it', 'de'].contains(locale.languageCode); } @override Future<AppLocalizations> load(Locale locale) async { // AppLocalizations class is where the JSON loading actually runs AppLocalizations localizations = new AppLocalizations(locale); await localizations.load(); return localizations; } @override bool shouldReload(_AppLocalizationsDelegate old) => false; }
Logcat日志
Rejecting re-init on previously-failed class java.lang.Class<io.flutter.embedding.engine.FlutterJNI$$ExternalSyntheticLambda0>: java.lang.NoClassDefFoundError: Failed resolution of: Landroid/graphics/ImageDecoder$OnHeaderDecodedListener; at io.flutter.embedding.engine.FlutterJNI io.flutter.embedding.engine.FlutterJNI$Factory.provideFlutterJNI() (FlutterJNI.java:123) at void io.flutter.FlutterInjector$Builder.fillDefaults() (FlutterInjector.java:169) at io.flutter.FlutterInjector io.flutter.FlutterInjector$Builder.build() (FlutterInjector.java:179) at io.flutter.FlutterInjector io.flutter.FlutterInjector.instance() (FlutterInjector.java:57) at void io.flutter.embedding.engine.FlutterEngine.<init>(android.content.Context, io.flutter.embedding.engine.loader.FlutterLoader, io.flutter.embedding.engine.FlutterJNI, io.flutter.plugin.platform.PlatformViewsController, java.lang.String[], boolean, boolean) (FlutterEngine.java:289) at void io.flutter.embedding.engine.FlutterEngine.<init>(android.content.Context, java.lang.String[], boolean, boolean) (FlutterEngine.java:207) at void io.flutter.embedding.android.FlutterActivityAndFragmentDelegate.setupFlutterEngine() (FlutterActivityAndFragmentDelegate.java:271) at void io.flutter.embedding.android.FlutterActivityAndFragmentDelegate.onAttach(android.content.Context) (FlutterActivityAndFragmentDelegate.java:180) at void io.flutter.embedding.android.FlutterActivity.onCreate(android.os.Bundle) (FlutterActivity.java:498) at void android.app.Activity.performCreate(android.os.Bundle) (Activity.java:6915) at void android.app.Instrumentation.callActivityOnCreate(android.app.Activity, android.os.Bundle) (Instrumentation.java:1123) at android.app.Activity android.app.ActivityThread.performLaunchActivity(android.app.ActivityThread$ActivityClientRecord, android.content.Intent) (ActivityThread.java:2746) at void android.app.ActivityThread.handleLaunchActivity(android.app.ActivityThread$ActivityClientRecord, android.content.Intent, java.lang.String) (ActivityThread.java:2864) at void android.app.ActivityThread.-wrap12(android.app.ActivityThread, android.app.ActivityThread$ActivityClientRecord, android.content.Intent, java.lang.String) (ActivityThread.java:-1) at void android.app.ActivityThread$H.handleMessage(android.os.Message) (ActivityThread.java:1567) at void android.os.Handler.dispatchMessage(android.os.Message) (Handler.java:105) at void android.os.Looper.loop() (Looper.java:156) at void android.app.ActivityThread.main(java.lang.String[]) (ActivityThread.java:6523) at java.lang.Object java.lang.reflect.Method.invoke!(java.lang.Object, java.lang.Object[]) (Method.java:-2) at void com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run() (ZygoteInit.java:942) at void com.android.internal.os.ZygoteInit.main(java.lang.String[]) (ZygoteInit.java:832) Caused by: java.lang.ClassNotFoundException: Didn't find class "android.graphics.ImageDecoder$OnHeaderDecodedListener" on path: DexPathList[[zip file "/data/app/com.xxxxx.xxxxx.dev-2/base.apk"],nativeLibraryDirectories=[/data/app/com.xxxxx.xxxxx.dev-2/lib/arm64, /data/app/com.xxxxx.xxxxx.dev-2/base.apk!/lib/arm64-v8a, /system/lib64, /vendor/lib64, /system/vendor/lib64, /product/lib64]] at java.lang.Class dalvik.system.BaseDexClassLoader.findClass(java.lang.String) (BaseDexClassLoader.java:56) at java.lang.Class java.lang.ClassLoader.loadClass(java.lang.String, boolean) (ClassLoader.java:380) at java.lang.Class java.lang.ClassLoader.loadClass(java.lang.String) (ClassLoader.java:312) at io.flutter.embedding.engine.FlutterJNI io.flutter.embedding.engine.FlutterJNI$Factory.provideFlutterJNI() (FlutterJNI.java:123) at void io.flutter.FlutterInjector$Builder.fillDefaults() (FlutterInjector.java:169) at io.flutter.FlutterInjector io.flutter.FlutterInjector$Builder.build() (FlutterInjector.java:179) at io.flutter.FlutterInjector io.flutter.FlutterInjector.instance() (FlutterInjector.java:57) at void io.flutter.embedding.engine.FlutterEngine.<init>(android.content.Context, io.flutter.embedding.engine.loader.FlutterLoader, io.flutter.embedding.engine.FlutterJNI, io.flutter.plugin.platform.PlatformViewsController, java.lang.String[], boolean, boolean) (FlutterEngine.java:289) at void io.flutter.embedding.engine.FlutterEngine.<init>(android.content.Context, java.lang.String[], boolean, boolean) (FlutterEngine.java:207) at void io.flutter.embedding.android.FlutterActivityAndFragmentDelegate.setupFlutterEngine() (FlutterActivityAndFragmentDelegate.java:271) at void io.flutter.embedding.android.FlutterActivityAndFragmentDelegate.onAttach(android.content.Context) (FlutterActivityAndFragmentDelegate.java:180) at void io.flutter.embedding.android.FlutterActivity.onCreate(android.os.Bundle) (FlutterActivity.java:498) at void android.app.Activity.performCreate(android.os.Bundle) (Activity.java:6915) at void android.app.Instrumentation.callActivityOnCreate(android.app.Activity, android.os.Bundle) (Instrumentation.java:1123) at android.app.Activity android.app.ActivityThread.performLaunchActivity(android.app.ActivityThread$ActivityClientRecord, android.content.Intent) (ActivityThread.java:2746) at void android.app.ActivityThread.handleLaunchActivity(android.app.ActivityThread$ActivityClientRecord, android.content.Intent, java.lang.String) (ActivityThread.java:2864) at void android.app.ActivityThread.-wrap12(android.app.ActivityThread, android.app.ActivityThread$ActivityClientRecord, android.content.Intent, java.lang.String) (ActivityThread.java:-1) at void android.app.ActivityThread$H.handleMessage(android.os.Message) (ActivityThread.java:1567) at void android.os.Handler.dispatchMessage(android.os.Message) (Handler.java:105) at void android.os.Looper.loop() (Looper.java:156) at void android.app.ActivityThread.main(java.lang.String[]) (ActivityThread.java:6523) at java.lang.Object java.lang.reflect.Method.invoke!(java.lang.Object, java.lang.Object[]) (Method.java:-2) at void com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run() (ZygoteInit.java:942) at void com.android.internal.os.ZygoteInit.main(java.lang.String[]) (ZygoteInit.java:832)
内容的提问来源于stack exchange,提问作者Sami Issa
相关产品推荐
相关产品推荐

