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

Flutter:iOS Release模式下后台本地通知不生效求助

iOS Release模式下flutter_local_notifications后台本地通知不显示问题

问题概述

使用flutter_local_notifications v16.1.0实现本地通知功能,Android全模式、iOS Debug模式均正常运行,但iOS Release模式下后台无法展示本地通知。

已完成排查

  • 确认使用最新版本flutter_local_notifications(v16.1.0)
  • 已开启iOS Debug/Release模式Signing & Capabilities中的Background modes权限(包含fetch、remote notifications)

实现代码

import 'dart:async';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';

class ReceivedNotification {
  ReceivedNotification({
    required this.id,
    required this.title,
    required this.body,
    required this.payload,
  });

  final int id;
  final String? title;
  final String? body;
  final String? payload;
}

/// 触发应用导航的通知动作
const String navigationActionId = 'id_3';

@pragma('vm:entry-point')
void notificationTapBackground(NotificationResponse notificationResponse) {
  // ignore: avoid_print
  print('通知(${notificationResponse.id})被点击: '
      '动作ID: ${notificationResponse.actionId}, '
      '负载: ${notificationResponse.payload}');
  if (notificationResponse.input?.isNotEmpty ?? false) {
    // ignore: avoid_print
    print('通知点击附带输入内容: ${notificationResponse.input}');
  }
}

class NotificationService {
  // 单例模式
  static final NotificationService _notificationService =
      NotificationService._internal();
  factory NotificationService() {
    return _notificationService;
  }
  NotificationService._internal();

  /// 创建流以响应通知相关事件(插件在main函数初始化)
  final StreamController<ReceivedNotification>
      didReceiveLocalNotificationStream =
      StreamController<ReceivedNotification>.broadcast();

  final StreamController<String?> selectNotificationStream =
      StreamController<String?>.broadcast();

  // FlutterLocalNotificationsPlugin实例
  final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
      FlutterLocalNotificationsPlugin();

  Future<void> initialize() async {
    const AndroidInitializationSettings initializationSettingsAndroid =
        AndroidInitializationSettings('@drawable/iclauncher');

    // iOS初始化设置
    final DarwinInitializationSettings initializationSettingsDarwin =
        DarwinInitializationSettings(
      requestSoundPermission: true,
      requestBadgePermission: true,
      requestAlertPermission: true,
      onDidReceiveLocalNotification:
          (int id, String? title, String? body, String? payload) async {
        didReceiveLocalNotificationStream.add(
          ReceivedNotification(
            id: id,
            title: title,
            body: body,
            payload: payload,
          ),
        );
      },
    );

    final InitializationSettings settings = InitializationSettings(
      android: initializationSettingsAndroid,
      iOS: initializationSettingsDarwin,
    );

    await flutterLocalNotificationsPlugin.initialize(
      settings,
      onDidReceiveNotificationResponse:
          (NotificationResponse notificationResponse) {
        switch (notificationResponse.notificationResponseType) {
          case NotificationResponseType.selectedNotification:
            selectNotificationStream.add(notificationResponse.payload);
            break;
          case NotificationResponseType.selectedNotificationAction:
            if (notificationResponse.actionId == navigationActionId) {
              selectNotificationStream.add(notificationResponse.payload);
            }
            break;
        }
      },
      onDidReceiveBackgroundNotificationResponse: notificationTapBackground,
    );
  }

  Future<NotificationDetails> _notificationDetails() async {
    const AndroidNotificationDetails androidNotificationDetails =
        AndroidNotificationDetails(
      'channel ID',
      'channel name',
      playSound: true,
      priority: Priority.high,
      importance: Importance.high,
    );

    const NotificationDetails notificationDetails =
        NotificationDetails(android: androidNotificationDetails);

    return notificationDetails;
  }

  Future<void> showNotification({
    required int id,
    required String title,
    required String body,
  }) async {
    final details = await _notificationDetails();
    await flutterLocalNotificationsPlugin.show(id, title, body, details);
  }
}

解决方向

  1. 补充iOS专属通知配置
    当前_notificationDetails()方法仅配置了Android端参数,iOS Release模式下需要明确配置弹窗、徽章、声音等权限,否则可能被系统拦截。修改该方法:
Future<NotificationDetails> _notificationDetails() async {
  const AndroidNotificationDetails androidNotificationDetails =
      AndroidNotificationDetails(
    'channel ID',
    'channel name',
    playSound: true,
    priority: Priority.high,
    importance: Importance.high,
  );
  // 添加iOS通知配置
  const DarwinNotificationDetails darwinNotificationDetails =
      DarwinNotificationDetails(
    presentAlert: true,
    presentBadge: true,
    presentSound: true,
  );

  const NotificationDetails notificationDetails =
      NotificationDetails(
        android: androidNotificationDetails,
        iOS: darwinNotificationDetails
      );

  return notificationDetails;
}
  1. 验证权限状态
    Release模式下需主动检查用户是否开启通知权限,避免权限被关闭导致通知无法展示:
// 在initialize方法中添加权限检查逻辑
final bool hasPermission = await flutterLocalNotificationsPlugin
    .resolvePlatformSpecificImplementation<IOSFlutterLocalNotificationsPlugin>()
    ?.requestPermissions(
      alert: true,
      badge: true,
      sound: true,
    ) ?? false;
if (!hasPermission) {
  // 提示用户前往设置开启通知权限
}
  1. 确认后台触发逻辑
    如果是定时触发通知,需使用zonedSchedule等支持后台调度的API,而非仅用show(show多用于前台即时触发)。同时确保应用处于后台活跃状态,完全退出后iOS系统不会触发本地通知。

  2. 检查Xcode编译配置

  • 确认Release模式下未开启Strip Debug Symbols During Copy等可能影响后台代码执行的选项
  • 验证Info.plist中已添加UIBackgroundModes字段,包含fetch和remote-notification值

内容的提问来源于stack exchange,提问作者Jean-Noël Aubry

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 00:16:06