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

静默推送无法触发didReceiveRemoteNotification问题排查求助

iOS后台推送未触发application(_:didReceiveRemoteNotification:fetchCompletionHandler:)问题排查与解决

问题背景

我们通过Firebase发送推送通知,其中部分推送需要向后端发送回执确认,因此采用后台通知类型,计划在iOS的application(_:didReceiveRemoteNotification:fetchCompletionHandler:)方法中发送消息ID至后端并展示通知,但该方法始终未被调用,功能失效。

已完成的配置与尝试:

  • 已启用Xcode中Background fetch和Remote Notifications后台模式
  • 常规可见通知可正常送达
  • 使用Capacitor及其PushNotifications插件
  • 尝试禁用FirebaseAppDelegateProxy但无效
  • 为AppDelegate添加UNUserNotificationCenterDelegate,仅前台收到可见通知时会触发didReceiveRemoteNotification

发送后台通知的后端Java代码:

final var apnsConfig =
        ApnsConfig.builder()
                .setAps(Aps.builder().setContentAvailable(true).build())
                .putAllHeaders(Map.of("apns-push-type", "background", "apns-priority", "5"))
                .putCustomData("customDataKey", "customDataValue")
                .build();

final var multicastMessageBuilder =
        MulticastMessage.builder()
                .setApnsConfig(apnsConfig)
                .addAllTokens(
                        fcmEntities.stream()
                                .map(FcmMessageEntity::getFcmRegistrationToken)
                                .toList());

multicastMessageBuilder.putAllData(
        Map.of(
                "notificationTitle",
                notificationTitle,
                "notificationBody",
                notificationBody));

final var batchResponse =
        FirebaseMessaging.getInstance(firebaseService.getFirebaseApp())
                .sendEachForMulticast(multicastMessageBuilder.build());

解决方案

1. 处理Capacitor插件的事件拦截

Capacitor的PushNotifications插件会接管AppDelegate的推送事件,默认不会将后台推送传递给原生的application(_:didReceiveRemoteNotification:fetchCompletionHandler:),需要手动在插件回调中处理:

原生端(AppDelegate.swift)处理

实现UNUserNotificationCenterDelegate的回调方法,直接在其中执行回执逻辑:

func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
    let userInfo = response.notification.request.content.userInfo
    
    // 识别后台推送
    if let aps = userInfo["aps"] as? [String: Any], aps["content-available"] as? Int == 1 {
        // 发送回执到后端
        if let messageId = userInfo["message_id"] as? String {
            sendReceiptToBackend(messageId: messageId)
        }
        // 手动展示本地通知
        if let title = userInfo["notificationTitle"] as? String, let body = userInfo["notificationBody"] as? String {
            let content = UNMutableNotificationContent()
            content.title = title
            content.body = body
            let request = UNNotificationRequest(identifier: UUID().uuidString, content: content, trigger: nil)
            UNUserNotificationCenter.current().add(request)
        }
    }
    
    completionHandler()
}

前端(Capacitor)处理

监听插件的pushNotificationReceived事件,触发回执逻辑:

import { PushNotifications } from '@capacitor/push-notifications';
import { Plugins } from '@capacitor/core';

PushNotifications.addListener('pushNotificationReceived', (notification) => {
  // 判断是否为后台推送
  if (notification.data['content-available'] === '1') {
    // 调用自定义原生插件发送回执
    Plugins.YourReceiptPlugin.sendReceipt({ 
      messageId: notification.data.message_id 
    });
    // 展示本地通知
    PushNotifications.schedule({
      title: notification.data.notificationTitle,
      body: notification.data.notificationBody,
      id: Date.now(),
    });
  }
});

2. 修正APNs推送配置

当前推送配置存在不符合APNs后台推送规范的问题:

  • apns-push-type与内容冲突:设置为background时,APNs不允许消息包含alert类可见通知字段,否则会被判定为无效后台推送。需移除notificationTitle、notificationBody这类字段,改为在后台回调中手动创建本地通知。
  • 仅保留必要数据:后台推送只传递回执所需的核心数据(如message_id),减少冗余字段干扰解析。

修正后的后端配置示例:

final var apnsConfig =
        ApnsConfig.builder()
                .setAps(Aps.builder().setContentAvailable(true).build())
                .putAllHeaders(Map.of("apns-push-type", "background", "apns-priority", "5"))
                .build();

final var multicastMessageBuilder =
        MulticastMessage.builder()
                .setApnsConfig(apnsConfig)
                .addAllTokens(fcmEntities.stream().map(FcmMessageEntity::getFcmRegistrationToken).toList())
                .putAllData(Map.of("message_id", "your-unique-message-id"));

final var batchResponse =
        FirebaseMessaging.getInstance(firebaseService.getFirebaseApp())
                .sendEachForMulticast(multicastMessageBuilder.build());

3. 调整Firebase与Capacitor的集成配置

  • 保留FirebaseAppDelegateProxy:禁用FirebaseAppDelegateProxyEnabled会破坏Capacitor与Firebase的事件传递,建议保持默认的YES配置。
  • 验证FCM令牌有效性:在Capacitor的pushNotificationRegistered事件中打印令牌,确保与后端存储的令牌一致。
  • 使用真实设备测试:iOS模拟器不支持后台推送测试,必须使用真实设备,且避免设备长时间锁定或处于低功耗模式(系统会限制后台活动)。

4. 检查系统权限限制

  • 关闭设备的低功耗模式:该模式会延迟或忽略后台推送。
  • 确认应用的后台应用刷新权限开启:前往设置 > 你的应用 > 后台应用刷新检查权限状态。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 00:23:16