Airship Flutter 推送点击失效(iOS)?看这里解决!
2025-01-23 00:50:18
Airship Flutter 推送通知点击在应用关闭时失效问题分析与解决(iOS)
使用 Urban Airship SDK 的 Flutter 应用中,推送通知点击跳转功能可能在应用完全关闭(从后台滑动退出)后失效。虽然应用在前台或后台时能正确响应通知点击,但在应用关闭后,相关的 onNotificationResponse
事件监听却无法触发,导致通知点击后未能实现预期跳转。这可能让用户体验大打折扣。本篇文章将探讨此问题,并给出解决方案。
问题根源
问题主要在于 iOS 应用的生命周期管理和通知处理机制。当应用被彻底关闭时,系统不会在后台直接运行应用内的代码来响应通知点击。通常,系统会先启动应用,然后应用需要初始化 Airship SDK 并设置相关的监听器,才能接收到通知事件。因此,如果应用在收到通知点击事件时未正确配置这些监听器,则相应的事件回调就不会被执行。
解决方案
以下提供几种解决此问题的方案,确保即使应用完全关闭,也能正常处理 Airship 推送通知点击:
1. 利用 Push.onLaunch
Urban Airship SDK 提供了 onLaunch
方法,该方法会在应用启动时,特别是通过点击通知启动时被调用。可以利用此方法检查是否存在待处理的通知,并进行相应的跳转操作。
-
实现步骤 :
- 在
main()
函数的Airship.takeOff
之后,以及在任何推送通知事件监听器设置之前,添加Airship.push.onLaunch
监听器。 - 在
onLaunch
事件处理中,检查event
对象是否为空。如果不为空,表示是由通知点击启动,则根据通知内容进行页面跳转或其他操作。 - 保留原有的
onNotificationResponse
监听,这样在前后台收到通知都可以正常处理
- 在
-
代码示例 :
import 'package:airship_flutter/airship_flutter.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
// Airship 初始化配置
var config = AirshipConfig(...);
Airship.takeOff(config);
// 在 onNotificationResponse 前监听onLaunch
Airship.push.onLaunch.listen((event) {
if (event != null) {
debugPrint("Launched from notification: $event");
// 这里可以根据通知内容处理跳转逻辑
// controller.animateTo(1);
}
});
// 原来的 NotificationResponse 监听
Airship.push.onNotificationResponse.listen((event) {
debugPrint('Notification Response $event');
// 移动 controller.animateTo(1)到launch里,在launch 里也做逻辑处理
//controller.animateTo(1);
});
runApp(MyApp());
}
- 操作步骤 :
- 修改
main.dart
文件,按上述示例修改。 - 重新编译安装到真机测试。
- 修改
- 解释 :
- 此方案确保在应用被关闭后由通知启动时,能够正确捕获并处理通知点击事件,并在此时执行跳转等操作。 同时保留
onNotificationResponse
处理,确保前台和后台时也可以正常处理跳转。
- 此方案确保在应用被关闭后由通知启动时,能够正确捕获并处理通知点击事件,并在此时执行跳转等操作。 同时保留
2. 处理通知的Payload(负载)
另一种策略是在发送通知时,将自定义数据附加在通知的 payload 中,以便应用在启动时读取并解析这些数据,根据自定义数据实现不同的页面跳转。
这可以让处理流程变得更为灵活,特别是需要根据通知中的某些信息来确定跳转目标的时候。
-
实现步骤 :
- 修改服务端发送通知的 payload。添加自定义键值对。
- 在
Airship.push.onLaunch
和Airship.push.onNotificationResponse
的监听器中,读取 payload 里面的数据,进行相应的路由跳转处理。
-
代码示例 :
发送推送示例 payload (服务端示例, 各推送服务有细微差别):{ "audience": "all", "device_types": [ "ios", "android" ], "notification": { "alert": "你的通知消息内容", "ios":{ "extras": { "screen_route": "/details" } } }, "push": { "aps":{ "content-available":1 //确保后台处理 } } }
flutter 代码处理
import 'package:airship_flutter/airship_flutter.dart'; import 'package:flutter/material.dart'; final GlobalKey<NavigatorState> key = GlobalKey(); // 注意 context 的问题 void handleRoute (Map? data) { String? routeName; if(data != null && data["extras"] != null){ routeName = (data["extras"] as Map)['screen_route']; } if(routeName != null){ // key 在最外层,并且保证有 context key.currentState?.pushNamed(routeName); } } void main() { WidgetsFlutterBinding.ensureInitialized(); var config = AirshipConfig(...); Airship.takeOff(config); Airship.push.onLaunch.listen((event) { // 注意 null 判断 if(event != null && event.notificationResponse != null && event.notificationResponse!.notification.extras != null ){ debugPrint('Launch from Notification with extras ${event.notificationResponse?.notification.extras}'); handleRoute(event.notificationResponse?.notification.extras); } }); Airship.push.onNotificationResponse.listen((event) { debugPrint('Notification Response $event'); if (event.notification.extras != null){ handleRoute(event.notification.extras); } }); runApp(MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, navigatorKey: key, // 这里保证 GlobalKey 的有效性 routes: { '/': (context) => const MyHomePage(), '/details': (context) => const DetailScreen(), } ); } } class MyHomePage extends StatelessWidget { const MyHomePage({super.key}); @override Widget build(BuildContext context) { return Scaffold(appBar: AppBar(title: const Text("home page"))); } }
class DetailScreen extends StatelessWidget {
const DetailScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(appBar: AppBar(title: const Text("details page")));
}
}
* **操作步骤** :
1. 按服务端示例调整通知Payload数据
2. 修改`main.dart` 文件,添加路由跳转相关逻辑。
3. 真机测试,检查是否跳转到对应页面
* **解释** :
* 这种方法提供了一种更为灵活的处理方式。它通过自定义通知数据,可以在任何时候修改页面跳转逻辑而无需改动代码。 注意 context 的有效性,和null判断。
## 额外建议
1. **代码健壮性** :确保所有可能为空的值在使用前进行检查,避免因为空指针或空值导致的崩溃。
2. **异常处理** : 在 `Airship` 方法调用以及页面跳转时添加 `try-catch` 代码块,以便捕获异常并进行处理。这对于稳定性和用户体验非常关键。
3. **测试** :在真实设备上测试确保各项逻辑的正常运行,包括在应用前后台,以及关闭重启后的表现。 使用 postman 或第三方推送服务发送消息。
## 总结
在 iOS 上,处理 Airship 推送通知点击涉及应用生命周期管理和 Airship SDK 事件监听。通过仔细配置 `Airship.push.onLaunch` 和 `Airship.push.onNotificationResponse` 事件,同时在通知负载中包含自定义信息,能解决应用完全关闭时无法跳转页面的问题。确保应用在各种情况下都能提供稳定可靠的推送通知响应体验。