Flutter Android FCM推送Debug正常Release失效,求解决方案
问题描述
使用Flutter SDK 3.3.5,Firebase依赖版本:firebase_core:2.1.1、firebase_crashlytics:3.0.4、firebase_messaging:14.0.3。Debug模式下Firebase Messaging功能正常,可获取Token且控制台推送成功,已配置Google Play的SHA-1/SHA-256并更新google-services.json,但Release模式下推送失效,运行时报错:
W/FlutterJNI(20984): FlutterJNI.init called more than once E/flutter (20984): [ERROR:flutter/runtime/dart_isolate.cc(668)] Could not resolve main entrypoint function. E/flutter (20984): [ERROR:flutter/runtime/dart_isolate.cc(168)] Could not run the run main Dart entrypoint. E/flutter (20984): [ERROR:flutter/runtime/runtime_controller.cc(396)] Could not create root isolate. E/flutter (20984): [ERROR:flutter/shell/common/shell.cc(606)] Could not launch engine with configuration. E/flutter (20984): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: [firebase_messaging/unknown] java.io.IOException: FIS_AUTH_ERROR E/flutter (20984): #0 StandardMethodCodec.decodeEnvelope (package:flutter/src/services/message_codecs.dart:653) E/flutter (20984): #1 MethodChannel._invokeMethod (package:flutter/src/services/platform_channel.dart:315) E/flutter (20984): E/flutter (20984): #2 MethodChannel.invokeMapMethod (package:flutter/src/services/platform_channel.dart:518) E/flutter (20984): E/flutter (20984): #3 MethodChannelFirebaseMessaging.getToken (package:firebase_messaging_platform_interface/src/method_channel/method_channel_messaging.dart:224) E/flutter (20984): E/flutter (20984): #4 FireBaseMessagingService.init (package:hr_max/Helpers/firebase_messaging_services.dart:44) E/flutter (20984): E/flutter (20984): #5 GetInstance.putAsync (package:get/get_instance/src/get_instance.dart:62) E/flutter (20984): E/flutter (20984): #6 MyApp.build. (package:hr_max/main.dart:158)
已尝试重新下载google-services.json,问题未解决。相关配置文件如下:
AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.initiummesolutions.hr_max"> <uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.CAMERA" /> <uses-feature android:name="android.hardware.camera" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.POST_NOTIFICATIONS"/> <application android:label="HR Max" android:icon="@mipmap/launcher_icon"> <activity android:name=".MainActivity" android:launchMode="singleTop" android:theme="@style/LaunchTheme" android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode" android:hardwareAccelerated="true" android:windowSoftInputMode="adjustResize" android:exported="true"> <meta-data android:name="io.flutter.embedding.android.NormalTheme" android:resource="@style/NormalTheme" /> <meta-data android:name="io.flutter.embedding.android.SplashScreenDrawable" android:resource="@drawable/launch_background" /> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> <!-- Don't delete the meta-data below. This is used by the Flutter tool to generate GeneratedPluginRegistrant.java --> <meta-data android:name="flutterEmbedding" android:value="2" /> </application> </manifest>
MainActivity.java
package com.initiummesolutions.hr_max; import io.flutter.embedding.android.FlutterActivity; public class MainActivity extends FlutterActivity { }
app/build.gradle
def localProperties = new Properties() def localPropertiesFile = rootProject.file('local.properties') if (localPropertiesFile.exists()) { localPropertiesFile.withReader('UTF-8') { reader -> localProperties.load(reader) } } def flutterRoot = localProperties.getProperty('flutter.sdk') if (flutterRoot == null) { throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") } def flutterVersionCode = localProperties.getProperty('flutter.versionCode') if (flutterVersionCode == null) { flutterVersionCode = '1' } def flutterVersionName = localProperties.getProperty('flutter.versionName') if (flutterVersionName == null) { flutterVersionName = '1.0' } apply plugin: 'com.android.application' apply plugin: 'com.google.gms.google-services' apply plugin: 'com.google.firebase.crashlytics' apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" def keystoreProperties = new Properties() def keystorePropertiesFile = rootProject.file('key.properties') if (keystorePropertiesFile.exists()) { keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) } android { compileSdkVersion 33 compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). applicationId "com.initiummesolutions.hr_max" minSdkVersion 21 targetSdkVersion 33 versionCode flutterVersionCode.toInteger() versionName flutterVersionName } buildToolsVersion "30.0.2" signingConfigs { release { keyAlias keystoreProperties['keyAlias'] keyPassword keystoreProperties['keyPassword'] storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null storePassword keystoreProperties['storePassword'] } } buildTypes { release { signingConfig signingConfigs.release } } } dependencies { implementation 'androidx.work:work-runtime-ktx:2.7.0' implementation platform('com.google.firebase:firebase-bom:31.0.3') } flutter { source '../..' }
解决方案
从报错信息和配置来看,问题集中在Release模式下的代码混淆、签名配置以及Firebase认证三个方面,按以下步骤排查修复:
1. 修复代码混淆问题
Release模式下开启混淆会导致Flutter入口函数或Firebase相关方法被混淆,无法正常初始化。在android/app/proguard-rules.pro中添加以下规则:
# Flutter相关规则 -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.** # Firebase相关规则 -keep class com.google.firebase.** { *; } -keep class com.google.android.gms.** { *; } -keep class com.google.firebase.messaging.** { *; } -dontwarn com.google.firebase.** -dontwarn com.google.android.gms.**
同时在app/build.gradle的release构建类型中确保混淆开启并指定规则文件:
buildTypes { release { signingConfig signingConfigs.release minifyEnabled true useProguard true proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } }
2. 确认签名证书的SHA值正确性
- 检查用于Release签名的
key.jks的SHA-1和SHA-256值,执行命令:keytool -list -v -keystore /path/to/your/key.jks - 确保Firebase控制台中添加的SHA值与上述命令输出完全一致,包括大小写,且对应正确的应用包名。
3. 确保google-services.json配置正确
- 重新下载Firebase控制台的
google-services.json,确认文件中的package_name与app/build.gradle的applicationId完全一致。 - 将文件放在
android/app/目录下,清理项目后重新构建:flutter clean flutter build apk --release
4. 调整Firebase初始化时机
报错中显示在GetInstance.putAsync中初始化Firebase Messaging,可能因初始化时机过早导致问题。修改初始化逻辑,确保先初始化firebase_core再初始化firebase_messaging:
// 在main函数中先初始化firebase_core void main() async { WidgetsFlutterBinding.ensureInitialized(); await Firebase.initializeApp(); runApp(const MyApp()); } // 在FireBaseMessagingService.init中延迟获取Token Future<void> init() async { // 确保firebase_core已初始化完成 await Future.delayed(const Duration(milliseconds: 500)); String? token = await FirebaseMessaging.instance.getToken(); // 后续逻辑... }
5. 检查Firebase BOM版本兼容性
当前使用的Firebase BOM 31.0.3与你的Flutter Firebase依赖版本是否匹配,建议将BOM版本升级到与依赖兼容的版本,例如:
implementation platform('com.google.firebase:firebase-bom:32.0.0')
同时同步更新Flutter端的Firebase依赖版本到对应兼容版。
内容的提问来源于stack exchange,提问作者MikeNabil

