如何在Expo应用关闭超过4小时后定时推送特定时间的通知
如何在Expo应用关闭超过4小时后定时推送特定时间的通知
看起来你已经搞定了基础的定时通知,现在就差加个“应用后台/关闭超4小时”的条件对吧?我来给你拆解下具体怎么实现,核心思路就是记录应用最后活跃的时间,然后在要触发通知的时候检查这个时间差是否符合要求。
1. 安装必要依赖
你需要用到持久化存储工具来保存活跃时间,还有后台任务管理器来实现带条件的定时触发。先执行安装命令:
npx expo install @react-native-async-storage/async-storage expo-task-manager
2. 记录应用最后活跃时间
我们要监听应用状态变化,当应用从前台切到后台/关闭时,把当前时间存到本地存储里;同时应用启动回到前台时,也更新一下活跃时间,确保记录的是最新的交互时间。
在你的根组件里添加以下代码:
import AsyncStorage from '@react-native-async-storage/async-storage'; import { AppState } from 'react-native'; import * as TaskManager from 'expo-task-manager'; // 监听应用状态 const [appState, setAppState] = useState(AppState.currentState); // 保存最后活跃时间到本地 const saveLastActiveTime = async () => { try { await AsyncStorage.setItem('lastActiveTime', Date.now().toString()); } catch (e) { console.error('保存活跃时间失败:', e); } }; useEffect(() => { const subscription = AppState.addEventListener('change', nextAppState => { // 当应用从活跃状态切换到后台/非活跃时,记录时间 if (appState === 'active' && nextAppState.match(/inactive|background/)) { saveLastActiveTime(); } setAppState(nextAppState); }); // 组件卸载时移除监听 return () => subscription.remove(); }, [appState]); // 应用启动时,先更新一次活跃时间 useEffect(() => { saveLastActiveTime(); }, []);
3. 创建后台任务检查条件并发送通知
直接用Expo的定时通知没法加条件判断,所以我们需要创建一个后台任务,让它在每天指定时间(比如8点)触发,然后在任务里检查活跃时间差,符合条件再发送通知。
添加后台任务的定义:
// 定义唯一的后台任务名称 const DAILY_REMINDER_TASK = 'dailyReminderTask'; // 注册后台任务 TaskManager.defineTask(DAILY_REMINDER_TASK, async () => { try { // 读取本地存储的最后活跃时间 const lastActiveTimeStr = await AsyncStorage.getItem('lastActiveTime'); if (!lastActiveTimeStr) return; const lastActiveTime = parseInt(lastActiveTimeStr, 10); const currentTime = Date.now(); // 计算时间差(小时) const hoursDiff = (currentTime - lastActiveTime) / (1000 * 60 * 60); // 满足超过4小时的条件,发送通知 if (hoursDiff > 4) { await Notifications.scheduleNotificationAsync({ content: { title: '你的专属提醒', body: '已经4小时没打开应用啦,快回来看看~', // 可自定义更多通知内容 }, trigger: null, // 立即发送 }); } } catch (e) { console.error('后台任务执行出错:', e); } });
4. 调度后台任务到指定时间
最后在应用启动时,请求必要权限并把后台任务调度到每天8点执行:
useEffect(() => { const setupTask = async () => { // 请求通知权限 const { status } = await Notifications.getPermissionsAsync(); if (status !== 'granted') { await Notifications.requestPermissionsAsync(); } // 检查任务是否已注册,避免重复调度 const isRegistered = await TaskManager.isTaskRegisteredAsync(DAILY_REMINDER_TASK); if (!isRegistered) { // 调度任务每天8点触发 await Notifications.scheduleNotificationAsync({ content: { // 这里的内容不会显示,仅作为后台任务的触发载体 title: '后台任务触发器', body: '请勿删除此通知配置', }, trigger: { hour: 8, minute: 0, repeats: true, // 每天重复 }, task: DAILY_REMINDER_TASK, // 指定触发的后台任务 }); } }; setupTask(); }, []);
一些注意点
- iOS后台限制:iOS对后台任务管控较严,长时间关闭应用后,定时任务可能被系统暂停,但日常使用场景下基本能正常触发。
- 测试方法:开发时可以用
TaskManager.executeTaskAsync(DAILY_REMINDER_TASK)手动触发任务,验证逻辑是否正确。 - 权限问题:一定要确保用户授予了通知权限,否则后台任务和通知都无法正常工作。
把这些代码整合到你的根组件里,替换原来的定时通知逻辑,就能实现你想要的功能啦!
备注:内容来源于stack exchange,提问作者Takodana
相关产品推荐
相关产品推荐

