iOS通过FCM接入APNs仅发data字段推送无通知弹窗问题排查
问题根因
这个是iOS平台APNs与FCM的交互机制差异导致的,不属于前后端代码bug:
- FCM给安卓发送仅带data字段的消息时,安卓应用可以自行接收消息后弹出通知
- 但iOS的系统通知必须依赖APNs载荷中aps字段的alert配置,仅带data的FCM消息属于静默推送,系统不会主动弹出通知,只会触发
didReceiveRemoteNotification回调交给应用自行处理。
你可以根据团队情况选择以下任意一种方案解决:
方案1:后端修改(推荐,成本最低,双端兼容)
不需要改动现有安卓逻辑,只需要在构造FCM消息时新增notification字段即可,FCM会自动将该字段内容转换为iOS APNs要求的aps.alert配置,触发系统自动弹通知。
- 首先修改
FcmMessageReq类,新增Notification结构:
@AllArgsConstructor @Builder @Getter public class FcmMessageReq { private boolean validate_only; private Message message; @Builder @AllArgsConstructor @Getter public static class Message { private String token; private Data data; // 新增Notification字段 private Notification notification; } @Builder @AllArgsConstructor @Getter public static class Data { private String movingPage; private String title; private String body; } // 新增Notification静态类 @Builder @AllArgsConstructor @Getter public static class Notification { private String title; private String body; } }
- 然后修改
makeMessage方法,构造消息时传入notification参数:
private String makeMessage(String deviceToken, String title, String body, String movingPage) { FcmMessageReq fcmMessage = FcmMessageReq.builder() .validate_only(false) .message( FcmMessageReq.Message.builder() .token(deviceToken) .data( FcmMessageReq.Data.builder() .movingPage(movingPage) .title(title) .body(body) .build() ) // 新增notification配置,不影响安卓原有逻辑 .notification( FcmMessageReq.Notification.builder() .title(title) .body(body) .build() ) .build() ) .build(); try { return objectMapper.writeValueAsString(fcmMessage); } catch (Exception exception) { log.error("{}", exception.getStackTrace()); return null; } }
方案2:iOS端修改(适用于后端无法调整的场景)
如果后端暂时没法改动代码,你可以在收到静默推送的回调里,手动触发本地通知弹出,操作如下:
- 首先确保App启动时已经申请了通知权限,在
didFinishLaunchingWithOptions中添加如下代码:
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { granted, error in if granted { application.registerForRemoteNotifications() } }
- 修改
didReceiveRemoteNotification方法,收到数据后手动构造本地通知弹出:
func application(_ application: UIApplication,didReceiveRemoteNotification userInfo: [AnyHashable: Any],fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) { print ("didreceiveremotenoti") print ("UIStart",userInfo,"UIFIN") // 取出data字段中的title和body if let title = userInfo["title"] as? String, let body = userInfo["body"] as? String, let movingPage = userInfo["movingPage"] as? String { // 构造本地通知内容 let content = UNMutableNotificationContent() content.title = title content.body = body content.sound = .default // 存储自定义参数,供用户点击通知后跳转逻辑使用 content.userInfo = ["movingPage": movingPage] // 触发本地通知 let request = UNNotificationRequest(identifier: UUID().uuidString, content: content, trigger: nil) UNUserNotificationCenter.current().add(request) { error in if let error = error { print("本地通知弹出失败:\(error)") completionHandler(.failed) return } completionHandler(.newData) } return } guard let aps = userInfo["aps"] as? [String: AnyObject] else { completionHandler(.failed) return } print ("APS START",aps,"APSFIN") completionHandler(.newData) }
注意:该方案受iOS静默推送配额限制,系统每日对静默推送的接收次数有上限,超出后消息会被丢弃,不适合高频推送或者营销类推送场景。
内容的提问来源于stack exchange,提问作者Kyongkun Kim
相关产品推荐
相关产品推荐

