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

Flutter iOS应用被杀状态下FCM主题通知处理不一致问题排查

Flutter iOS FCM主题消息在应用终止状态下送达不一致的解决方案

核心问题分析

你的代码中APNS配置存在冲突:使用了background类型的推送,但同时包含了notification字段。iOS中,background推送属于静默推送,不会展示通知,且在应用终止状态下触发限制极多(每日次数受限、依赖用户近期活跃度);而你需要的是带通知的推送,必须使用alert推送类型。此外,apns-topic配置错误,使用了插件的Bundle ID而非你的应用实际Bundle ID,这也会导致推送无法正确路由到你的应用。


修复步骤

1. 修正APNS推送配置

将推送类型改为alert,修正apns-topic为你的应用Bundle ID,调整相关字段以匹配iOS推送规则:

router.post('/', (req, res) => {
    const topic = "ios-scheduling";
    const body = req.body;

    console.log("Request Body", req.body);

    const message = {
        notification: {
            title: "OsuniO",
            body: "You may have some pending tasks.",
        },
        data: {
            "notificationType": body['notificationType']
        },
        apns: {
            payload: {
                aps: {
                    alert: {
                        title: "OsuniO",
                        body: "You may have some pending tasks."
                    },
                    contentAvailable: true, // 唤醒应用执行后台处理
                    "interruption-level": "time-sensitive" // 确保专注模式下也能显示通知
                }
            },
            headers: {
                "apns-push-type": "alert", // 改为通知类型推送
                "apns-priority": "10", // 通知推送需设为最高优先级
                "apns-topic": "com.yourcompany.osunio" // 替换为你的应用实际Bundle ID
            }
        },
        topic: topic
    };

    console.log("message to be sent to the user: ", message);

    admin.messaging().send(message)
        .then((response) => {
            console.log('Successfully sent message:', response);
            res.status(200).json(message);
        })
        .catch((error) => {
            console.log('Error sending message:', error);
            res.status(400).json({ message: error }).end();
        });
});

module.exports = router;

2. 配置iOS权限与后台模式

  • 请求正确的通知权限:在Flutter初始化时请求完整通知权限,确保应用能在终止状态下接收推送:
    void main() async {
      WidgetsFlutterBinding.ensureInitialized();
      await Firebase.initializeApp();
      
      // 请求通知权限
      await FirebaseMessaging.instance.requestPermission(
        alert: true,
        badge: true,
        sound: true,
        provisional: true, // 可选:允许临时通知,无需用户立即授权
      );
      
      FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
      runApp(MyApp());
    }
    
  • 开启Xcode后台模式:在Xcode中,进入项目Signing & Capabilities,添加Background Modes并勾选Remote notifications。
  • 验证Info.plist配置:确保Info.plist包含以下配置,允许应用在后台接收推送:
    <key>UIBackgroundModes</key>
    <array>
        <string>remote-notification</string>
    </array>
    

3. 确保主题订阅的持久性

iOS上FCM主题订阅是持久化的,但应用重装后会丢失。建议在应用每次启动时执行订阅逻辑,避免订阅失效:

Future<void> _subscribeToTopic() async {
  await FirebaseMessaging.instance.subscribeToTopic("ios-scheduling");
}

// 在应用初始化或首页initState中调用
@override
void initState() {
  super.initState();
  _subscribeToTopic();
}

4. 正确实现后台处理回调

如果需要在应用终止状态下执行后台逻辑,必须将onBackgroundMessage回调定义为顶级函数(不能放在Widget类内部):

// 顶级函数
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
  await Firebase.initializeApp();
  // 执行后台处理逻辑,比如同步数据、调用API等
  print("处理后台消息: ${message.messageId}");
}

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();
  // 注册后台消息处理器
  FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
  runApp(MyApp());
}

5. 用真实设备测试

iOS模拟器对应用终止状态下的推送支持有限,必须使用真实设备测试。测试前确保:

  • 设备网络正常(Wi-Fi或蜂窝数据)
  • 应用未被用户在系统设置中禁用通知
  • 近期有打开过应用(iOS会限制长期未使用应用的推送)

内容的提问来源于stack exchange,提问作者Shivansh Rastogi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 22:05:58