Expo-notifications:应用关闭/后台状态下通知响应异常问题
问题解答
是的,必须集成expo-task-manager才能解决应用后台/关闭状态下的通知响应问题。
原因说明
你当前使用的addNotificationResponseReceivedListener是前台专用监听器,它依赖应用的JS线程处于活跃状态才能触发。当应用退到后台或完全关闭时,JS线程会被挂起甚至终止,这个监听器自然无法工作。而expo-task-manager的作用是注册由原生系统触发的后台任务——即使JS线程未启动,原生层也能直接触发任务执行你的响应逻辑。
具体实现步骤
1. 安装依赖
确保已安装所需包:
npx expo install expo-task-manager expo-notifications
2. 定义后台任务
在你的notificationServices文件中添加后台任务定义,注意任务名称要全局唯一:
import * as TaskManager from 'expo-task-manager'; import * as Notifications from 'expo-notifications'; // 定义后台任务,任务名称要与后续配置一致 TaskManager.defineTask('NOTIFICATION_RESPONSE_TASK', async ({ data, error }) => { if (error) { console.error('后台任务执行出错:', error); return; } if (data?.response) { const { response } = data; // 复用你原来的通知响应逻辑 if (response.actionIdentifier === "response1") { // 注意:friendToken和nickname需要从通知data中获取,或提前存在本地存储 const message = { to: friendToken, sound: "default", title: `${nickname} sent you a message`, body: "Test", data: {}, ios: { _displayInForeground: true }, }; try { await fetch("https://exp.host/--/api/v2/push/send", { method: "POST", headers: { Accept: "application/json", "Accept-encoding": "gzip, deflate", "Content-Type": "application/json", }, body: JSON.stringify(message), }); } catch (error) { console.log(error); } } } });
3. 配置通知类别并关联后台任务
修改setNotificationCategoryPumping函数,在定义通知按钮时绑定后台任务:
export const setNotificationCategoryPumping = () => { Notifications.setNotificationCategoriesAsync([ { identifier: 'pumping_category', actions: [ { identifier: 'response1', title: '响应按钮', options: { ios: { foregroundPresentationOptions: { alert: true, sound: true }, // iOS指定触发的后台任务 runTask: 'NOTIFICATION_RESPONSE_TASK', }, android: { channelId: 'your_custom_channel', // 需提前创建通知渠道 autoCancel: true, }, }, }, ], }, ]); };
4. 注册后台任务并保留前台监听器
在应用初始化的useEffect中注册后台任务,同时保留前台监听器处理活跃状态下的响应:
useEffect(() => { // 注册后台任务 TaskManager.registerTaskAsync('NOTIFICATION_RESPONSE_TASK') .catch(error => console.error('后台任务注册失败:', error)); // 保留前台监听器,处理应用活跃时的通知响应 responseListener.current = notificationServices.addNotificationResponseReceivedListener(customUser!); // 你的原有注册推送、设置类别等代码... return () => { // 清理订阅和任务注册 if (responseListener.current) { Notifications.removeNotificationSubscription(responseListener.current); } TaskManager.unregisterTaskAsync('NOTIFICATION_RESPONSE_TASK') .catch(error => console.error('后台任务注销失败:', error)); }; }, []);
关键修复点
你原有代码中addNotificationResponseReceivedListener的回调未加async,导致await fetch无法正常执行,需修正:
export const addNotificationResponseReceivedListener = (customUser: CustomUser) => { return Notifications.addNotificationResponseReceivedListener(async (response) => { // 这里添加async if (response.actionIdentifier === "response1") { // 原有逻辑现在可以正常使用await } }); };
内容的提问来源于stack exchange,提问作者Lars Eivind
相关产品推荐
相关产品推荐

