You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter中Firebase Messaging订阅Topic偶现SERVICE_NOT_AVAILABLE错误求助

问题:APP启动订阅Firebase Topic偶发[SERVICE_NOT_AVAILABLE]错误

APP启动时尝试让用户订阅指定Topic以接收通知,但存在偶发性问题:有时订阅成功,有时抛出错误[firebase_messaging/unknown] java.io.IOException: SERVICE_NOT_AVAILABLE。

相关代码

@override
void initState() {
  super.initState();

  lifeCycleHandler();

  WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
   
    ...

    await ini(context);

  });
}

Future<void> ini(BuildContext context) async {
   ...

   
    FirebaseMessaging.instance.subscribeToTopic(topic).whenComplete(() {
       debugPrint('successfully subscribed to $topic');
    },).onError((error, stackTrace) {
       debugPrint('an error occurred while subscribing to topic $topic \n $stackTrace \n error $error');
},);

   
}

错误日志

E/flutter (17003): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: [firebase_messaging/unknown] java.io.IOException: SERVICE_NOT_AVAILABLE
E/flutter (17003): #0 StandardMethodCodec.decodeEnvelope (package:flutter/src/services/message_codecs.dart:653:7)
E/flutter (17003): #1 MethodChannel._invokeMethod (package:flutter/src/services/platform_channel.dart:315:18)
E/flutter (17003):
E/flutter (17003): #2 MethodChannel.invokeMapMethod (package:flutter/src/services/platform_channel.dart:518:43)
E/flutter (17003):
E/flutter (17003): #3 MethodChannelFirebaseMessaging.deleteToken (package:firebase_messaging_platform_interface/src/method_channel/method_channel_messaging.dart:192:7)
E/flutter (17003):
E/flutter (17003): #4 MyMenuState.initToken (package:buffet/Screens/menu.dart:3250:5)
E/flutter (17003):
E/flutter (17003): #5 MyMenuState.ini (package:buffet/Screens/menu.dart:1682:5)
E/flutter (17003):
E/flutter (17003): #6 MyMenuState.initState. (package:buffet/Screens/menu.dart:132:7)
E/flutter (17003):

解决方案

1. 等Firebase初始化完成再订阅

当前代码在页面帧回调里执行订阅,但Firebase Messaging可能还没完全初始化。先确保Firebase核心加载完成再操作:

Future<void> ini(BuildContext context) async {
  // 先等待Firebase初始化
  await Firebase.initializeApp();
  
  try {
    await FirebaseMessaging.instance.subscribeToTopic(topic);
    debugPrint('successfully subscribed to $topic');
  } catch (error, stackTrace) {
    debugPrint('an error occurred while subscribing to topic $topic \n $stackTrace \n error $error');
  }
}

2. 加重试机制

SERVICE_NOT_AVAILABLE大多是临时网络波动或服务未就绪导致的,加指数退避重试能解决偶发问题:

Future<void> subscribeWithRetry(String topic, int retryCount) async {
  try {
    await FirebaseMessaging.instance.subscribeToTopic(topic);
    debugPrint('successfully subscribed to $topic');
  } catch (e) {
    if (retryCount > 0 && e.toString().contains('SERVICE_NOT_AVAILABLE')) {
      // 指数退避,每次等待时间翻倍
      await Future.delayed(Duration(seconds: (4 - retryCount) * 2));
      await subscribeWithRetry(topic, retryCount - 1);
    } else {
      debugPrint('Failed to subscribe after retries: $e');
    }
  }
}

// 在ini方法里调用
Future<void> ini(BuildContext context) async {
  await Firebase.initializeApp();
  await subscribeWithRetry(topic, 3); // 最多重试3次
}

3. 提前检查网络状态

订阅前先确认设备有可用网络,避免无网导致的服务不可用错误:

import 'package:connectivity_plus/connectivity_plus.dart';

Future<void> ini(BuildContext context) async {
  await Firebase.initializeApp();
  
  var connectivityResult = await (Connectivity().checkConnectivity());
  if (connectivityResult == ConnectivityResult.none) {
    debugPrint('No internet connection, cannot subscribe to topic');
    return;
  }
  
  try {
    await FirebaseMessaging.instance.subscribeToTopic(topic);
    debugPrint('successfully subscribed to $topic');
  } catch (error, stackTrace) {
    debugPrint('an error occurred while subscribing to topic $topic \n $stackTrace \n error $error');
  }
}

4. 避免令牌操作和订阅冲突

从错误日志看,订阅过程中还调用了deleteToken,这可能干扰订阅流程。要么确保令牌操作完成后再订阅,要么调整两者的执行顺序,避免资源竞争。

内容的提问来源于stack exchange,提问作者Abdalla Tawfik

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 18:25:29