Ionic/Cordova iOS应用关闭时onNotificationOpen回调不触发问题排查
解决iOS Ionic/Cordova应用终止状态下推送点击无响应的问题
我之前也踩过这个坑!问题核心在于cordova-plugin-firebase的事件机制差异:当应用处于前台或后台未被杀死时,onNotificationOpen能正常捕获点击事件,但如果应用是从完全终止/关闭状态被推送唤醒的,推送数据不会通过onNotificationOpen返回,而是需要通过getInitialNotification()方法在应用启动时主动获取。
问题根源
iOS系统在应用终止状态下收到推送并被点击时,会直接启动应用,此时推送的初始数据会被存在启动上下文里,而不是触发实时的onNotificationOpen事件——这个方法只负责监听应用运行中的推送交互。
具体解决方案
我们需要修改你的代码,添加对初始推送的处理,同时优化监听逻辑避免重复订阅:
1. 更新push.provider.ts代码
import { Injectable } from '@angular/core'; import { Firebase } from '@ionic-native/firebase'; import { Platform } from 'ionic-angular'; @Injectable() export class PushNotificationsProvider { // 标记是否已初始化监听,避免重复订阅导致多次触发 private listenersInitialized = false; constructor (private firebase: Firebase, private platform: Platform) { } init () { if (!this.platform.is('cordova')) { return; } // 统一处理权限验证后的推送初始化逻辑 const setupPush = async () => { // 第一步:检查是否是从推送点击启动应用(终止状态) const initialNotification = await this.firebase.getInitialNotification(); if (initialNotification) { // 标记为后台点击,复用现有处理逻辑 this.handleNotification({ ...initialNotification, tap: true }); } // 第二步:初始化运行时的推送监听 this.initListeners(); }; if (this.platform.is('ios')) { this.firebase.grantPermission() .then(setupPush) .catch(err => console.error('iOS权限申请失败:', err)); } else if (this.platform.is('android')) { this.firebase.hasPermission() .then(data => { if (data && data.isEnabled) { setupPush(); } else { // 可选:Android无权限时引导用户开启 this.firebase.grantPermission().then(setupPush); } }) .catch(err => console.error('Android权限检查失败:', err)); } } initListeners () { if (this.listenersInitialized) return; this.listenersInitialized = true; this.firebase.onNotificationOpen().subscribe((notification: any) => { this.handleNotification(notification); }); } handleNotification (notification) { if (!notification) { return; } const message = (notification.aps || {}).alert || '无推送内容'; if (notification.tap) { console.log('*** FMC: 从后台/终止状态打开推送:', notification); alert('*** FMC: opened in background/terminated: ' + message); // 这里添加页面导航逻辑,比如根据自定义字段跳转 // this.navCtrl.push('TargetPage', { id: notification.customData.id }); } else { console.log('*** FMC: 前台收到推送:', notification); alert('*** FMC: opened in foreground: ' + message); } } }
2. 优化app.component.ts的初始化逻辑
你之前在platform.resume里重复调用init(),现在因为加了listenersInitialized标记,不会重复订阅,但可以保留调用确保权限变化后能重新初始化:
this.platform.ready().then(() => { if (this.platform.is('cordova')) { this.pushProvider.init(); this.platform.resume.subscribe(() => { this.pushProvider.init(); }); } });
3. 确保推送Payload格式正确
iOS下的推送Payload必须包含aps字段,自定义导航数据要放在根节点(不要嵌套在aps里),示例Payload:
{ "aps": { "alert": "您有新的消息", "sound": "default", "badge": 1 }, "customData": { "targetPage": "OrderDetailPage", "orderId": "123456" } }
4. 可选:升级插件版本
你当前使用的cordova-plugin-firebase@1.0.2版本较旧,可能存在iOS推送兼容性问题。建议升级到^2.0.5版本,同时对应升级@ionic-native/firebase到^5.x.x(Ionic 3推荐@ionic-native/firebase@5.36.0)。
验证步骤
- 完全关闭应用(从后台划掉)
- 发送符合格式的推送通知
- 点击通知启动应用,此时应该能触发
handleNotification并执行后台/终止状态的逻辑
内容的提问来源于stack exchange,提问作者Remi Sture
相关产品推荐
相关产品推荐

