You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Expo React Native本地通知异常:未按计划执行却立即触发

Expo React Native 本地通知调度异常问题

我基于Expo开发React Native应用,尝试配置每日重复本地通知,遇到以下问题:

  • 通知ID能生成,但通知会立即触发,而非按设定的20:10执行
  • 调用Notifications.getAllScheduledNotificationsAsync()获取已调度通知时返回空数组
  • 已在权限申请成功后调用scheduleDailyNotification(),开发模式下问题仍存在

代码如下:

import * as Notifications from 'expo-notifications';
import { Alert, Platform } from 'react-native';
import Constants from "expo-constants";
import * as Device from 'expo-device';

Notifications.setNotificationHandler({
    handleNotification: async () => ({
        shouldShowAlert: true,  // ✅ Ensures the notification is displayed
        shouldPlaySound: true,  // ✅ Enables sound
        shouldSetBadge: false,  // ❌ No badge update
    }),
});

async function createNotificationChannel() {
    if (Platform.OS === 'android') {
        await Notifications.setNotificationChannelAsync('default', {
            name: 'Default Channel',
            importance: Notifications.AndroidImportance.MAX,
            vibrationPattern: [0, 250, 250, 250],
            lightColor: '#FF231F7C',
        });
    }
}

// ✅ Request Notification Permission and return boolean status
async function requestNotificationPermission() {
    const { status } = await Notifications.getPermissionsAsync();
    Alert.alert("🔍 Initial Permission Status", status); // ✅ Show initial permission status
    console.log("🔍 Initial Permission Status", status);

    if (status !== 'granted') {
        const { status: newStatus } = await Notifications.requestPermissionsAsync();
        Alert.alert("📢 New Permission Status", newStatus); // ✅ Show new permission status
        console.log("📢 New Permission Status", newStatus);

        if (newStatus !== 'granted') {
            Alert.alert('❌ Permission Denied', 'Notifications are disabled.');
            return false;
        }
    }
    
    return true;
}

// ✅ Schedule Daily Notification
async function scheduleDailyNotification() {
    await createNotificationChannel();
    await Notifications.cancelAllScheduledNotificationsAsync(); // Clears old schedules to prevent duplicates

    await Notifications.scheduleNotificationAsync({
        content: {
            title: "Daily Reminder",
            body: "It is a scheduled notification!",
            sound: "default",
            priority: Notifications.AndroidNotificationPriority.MAX,
        },
        trigger: {
            hour: 20, // ✅ 8:10 PM (24-hour format)
            minute: 10,
            repeats: true, // 🔄 Repeat every day
            useUTC: false,
        },
    });

    // ✅ Fetch all scheduled notifications to verify it's scheduled
        const scheduled = await Notifications.getAllScheduledNotificationsAsync();
        console.log("📅 Scheduled Notifications:", scheduled);
        if (scheduled.length > 0) {
            Alert.alert("✅ Notification Scheduled", `Next reminder at 3:00 PM`);
        } else {
            Alert.alert("❌ No Notifications Scheduled", "Something went wrong.");
        }
}

export { scheduleDailyNotification };

问题排查与修复方案

1. 立即触发的原因及解决

当设置的每日触发时间(20:10)早于当前设备时间时,Expo的重复触发器会立即补触发一次,之后才会在每天的20:10执行。这是框架默认行为,若要避免,需判断当前时间是否已过设定点,若已过则将触发日期设为次日:

const now = new Date();
const triggerHour = 20;
const triggerMinute = 10;
let triggerDate = new Date(now.getFullYear(), now.getMonth(), now.getDate(), triggerHour, triggerMinute);

// 如果当前时间已过设定点,设置为次日
if (now > triggerDate) {
  triggerDate.setDate(triggerDate.getDate() + 1);
}

// 使用date触发器替代hour/minute
await Notifications.scheduleNotificationAsync({
  content: {...},
  trigger: {
    date: triggerDate,
    repeats: true,
    useUTC: false,
  },
});

2. 调度通知为空的修复点

  • 显式关联通知频道:Android上需在通知内容中指定channelId,否则调度可能失败:
    content: {
      title: "Daily Reminder",
      body: "It is a scheduled notification!",
      sound: "default",
      priority: Notifications.AndroidNotificationPriority.MAX,
      channelId: 'default' // 新增该行,关联创建的通知频道
    },
    
  • 确认权限校验逻辑:确保只有在权限获取成功后才调用调度函数,在调用处添加判断:
    // 调用示例
    const hasPermission = await requestNotificationPermission();
    if (hasPermission) {
      await scheduleDailyNotification();
    }
    
  • 开发模式调试技巧:
    1. 重启Expo Go应用和开发服务器
    2. 检查设备时区与useUTC: false匹配,设备时间需准确
    3. 暂时注释cancelAllScheduledNotificationsAsync(),避免清空未确认的调度
  • 验证调度结果:打印scheduleNotificationAsync的返回值,确认通知ID是否生成:
    const notificationId = await Notifications.scheduleNotificationAsync({...});
    console.log("生成的通知ID:", notificationId);
    

3. 额外注意事项

  • iOS上需确保在app.json中配置通知权限:
    "ios": {
      "infoPlist": {
        "UIBackgroundModes": ["notifications"]
      }
    }
    
  • 真机测试:Expo Go在模拟器上的通知调度可能存在限制,建议用真机测试

内容的提问来源于stack exchange,提问作者Tasneem

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 14:30:03