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

Xamarin使用LocalNotifications插件实现页面加载后弹出通知

问题核心原因

你遇到的通知不弹出问题不是单一原因导致的,核心有4个问题:

  • 生命周期调用顺序错误:重写OnAppearing时你把base.OnAppearing()放在了方法末尾,Xamarin.Forms要求重写生命周期方法时必须首先调用基类实现,否则页面未完成可视化树挂载,本地通知插件拿不到平台端的Activity/UIViewController上下文,调用Show方法时会被静默丢弃。
  • 调用时机过早:OnAppearing触发时页面还处于渲染过渡阶段,此时同步调用系统通知API会和页面渲染抢占UI线程资源,多数平台下插件会直接跳过执行。
  • 异步异常被吞噬:async void标记的生命周期方法不会向外抛出异常,Show方法内部抛出的上下文无效、权限不足等异常会被直接忽略,表现为代码执行到该行就直接跳过、无任何报错。
  • 异步初始化时序不可控:你在ViewModel构造函数里用Task.Run以fire-and-forget模式跑通知入库逻辑,属于非阻塞调用,虽然测试时能查到数据,但存在概率性的入库未完成就触发查库的问题,会导致偶发漏弹通知。
    另外你代码里foreach (Event event in eventList)用了C#保留关键字event作为变量名,也存在隐性解析风险。
分步修复方案

1. 修正OnAppearing方法逻辑

调整基类调用顺序,增加页面渲染等待时间,加上主线程调度和异常捕获,代码如下:

protected override async void OnAppearing()
{
    // 必须第一行调用基类方法,确保页面生命周期正常挂载
    base.OnAppearing();

    try
    {
        // 等待300ms让页面完成渲染、导航栈稳定,避免抢占UI线程
        await Task.Delay(300);

        // 先等待ViewModel完成通知入库逻辑,避免时序竞争
        if (BindingContext is MainPageViewModel vm)
        {
            await vm.InitializeAsync();
        }

        var notifications = await DatabaseService.db.Table<Notifications>().ToListAsync();
        
        if (notifications.Count > 0)
        {
            foreach (Notifications notification in notifications)
            {
                // 强制在UI主线程调用通知API,满足平台端线程要求
                Device.BeginInvokeOnMainThread(() =>
                {
                    CrossLocalNotifications.Current.Show(
                        "Reminder",
                        $"Event {notification.Name} is {notification.Occurrence} Today on {notification.NotifyDate}"
                    );
                });
            }
        }
    }
    catch (Exception ex)
    {
        // 调试时在这里打断点,可以捕获之前被吞噬的异常
        Debug.WriteLine($"Notification show failed: {ex}");
    }
}

2. 重构ViewModel的异步初始化逻辑

移除构造函数里的fire-and-forget异步调用,改为公开可等待的初始化方法,避免时序不可控问题:

public class MainPageViewModel
{
    private bool _isInitialized;

    public MainPageViewModel()
    {
        // 构造函数里不要直接执行异步逻辑
    }

    /// <summary>
    /// 页面加载时主动调用的异步初始化方法
    /// </summary>
    public async Task InitializeAsync()
    {
        // 加锁避免重复执行初始化
        if (_isInitialized) return;
        _isInitialized = true;

        await CheckNotifications();
    }

    private async Task CheckNotifications()
    {
        await DatabaseService.Init();
        var eventList = await DatabaseService.db.Table<Event>().ToListAsync();
            
        if (eventList.Count > 0)
        {
            // 注意不要用关键字event作为变量名,改为eventItem
            foreach (Event eventItem in eventList)
            {
                if (eventItem.NotifyStartDate && eventItem.StartDate.Date == DateTime.Today)
                {
                    Notifications notification = new Notifications
                    {
                        Name = $"{eventItem.Name}",
                        NotifyDate = eventItem.StartDate,
                        Occurrence = "Starting"
                    };
                    await DatabaseService.AddNotification(notification);
                }
                if (eventItem.NotifyEndDate && eventItem.EndDate.Date == DateTime.Today)
                {
                    Notifications notification = new Notifications
                    {
                        Name = $"{eventItem.Name}",
                        NotifyDate = eventItem.EndDate,
                        Occurrence = "Ending"
                    };
                    await DatabaseService.AddNotification(notification);
                }
            }
        } 
    }
}

3. 确认插件和平台配置

  • Android端:在MainActivity的OnCreate方法中确保LocalNotifications插件已完成初始化,Android 13及以上版本必须动态申请PostNotifications运行时权限,否则通知会被系统拦截。
  • iOS端:在AppDelegate的FinishedLaunching方法中完成插件初始化,首次启动时主动请求用户通知授权,用户同意后才能弹出通知。
  • 不要在App类构造函数中执行异步导航,此时应用平台端上下文未完成初始化,异步逻辑会被同步上下文阻塞。
额外注意
  • async void仅可用于重写生命周期方法,其他场景一律使用async Task作为异步方法返回值,避免异常被吞噬无法排查。
  • 所有调用系统API、UI相关的逻辑,尽量用Device.BeginInvokeOnMainThread包裹,确保运行在主线程,避免跨线程调用异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 17:39:19