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

Xamarin.Forms iOS如何在本地通知显示前修改标题与正文

核心原因

你之前的两种尝试不生效,本质是没摸透iOS本地通知的运行机制:

  • 修改iOSNotificationReceiver里传入ReceiveNotification()的标题、消息参数,只会改动C#业务层接收到事件时拿到的数据,系统弹出通知时读取的是你当初调度通知时写入UNNotification对象的原始内容,改动事件参数完全不会影响实际展示效果。
  • 直接在NotificationReceived?.Invoke(null, args);前return拦不住原始通知,是因为你没有正确调用系统回调。iOS前台通知代理方法要求必须执行传入的completionHandler,明确告知系统要如何处理当前通知,你不传递正确的拦截标识,系统默认就会按原始内容弹出。
实现步骤

分场景处理,覆盖前台、后台、App杀进程所有触发情况:

1. 前台通知动态修改

在iOS项目的UNUserNotificationCenter代理的WillPresentNotification方法中按如下逻辑实现:

[Export("userNotificationCenter:willPresentNotification:withCompletionHandler:")]
public void WillPresentNotification(UNUserNotificationCenter center, UNNotification notification, Action<UNNotificationPresentationOptions> completionHandler)
{
    var request = notification.Request;
    // 替换为你自己的每日通知标识前缀
    if (request.Identifier.StartsWith("DailyNotification_"))
    {
        // 拉取最新API数据,组装新的通知内容
        var newContent = new UNMutableNotificationContent
        {
            Title = "从API获取的最新标题",
            Body = "从API获取的最新正文",
            Sound = UNNotificationSound.Default,
            UserInfo = request.Content.UserInfo // 保留原始通知携带的自定义参数
        };

        // 关键:传入None告诉系统不要展示原始通知
        completionHandler(UNNotificationPresentationOptions.None);

        // 插入0.1秒后触发的新通知,用户无感知,不会出现叠弹
        var trigger = UNTimeIntervalNotificationTrigger.CreateTrigger(0.1, false);
        var newRequest = UNNotificationRequest.FromIdentifier(request.Identifier, newContent, trigger);
        center.AddNotificationRequest(newRequest, null);
    }
    else
    {
        // 其他通知按原有逻辑正常展示
        completionHandler(UNNotificationPresentationOptions.Alert | UNNotificationPresentationOptions.Sound);
    }
}

2. 后台/杀进程状态下动态修改

前台代理方法在App不在前台运行时不会生效,这种场景必须通过iOS官方提供的Notification Service Extension实现通知内容修改,这是唯一合规的方案:

  • 右键iOS解决方案添加新项目,选择Notification Service Extension模板,注意扩展的最低部署版本不能高于主App的最低支持版本
  • 在扩展的DidReceiveNotificationRequest方法中实现内容修改逻辑:
UNMutableNotificationContent BestAttemptContent;
Action<UNNotificationContent> ContentHandler;

public override void DidReceiveNotificationRequest(UNNotificationRequest request, Action<UNNotificationContent> contentHandler)
{
    ContentHandler = contentHandler;
    BestAttemptContent = (UNMutableNotificationContent)request.Content.MutableCopy();

    if (request.Identifier.StartsWith("DailyNotification_"))
    {
        // 两种方式拿最新内容:
        // 1. 开启App Group能力,从主App和扩展共享的存储空间中,读取主App提前拉取好的最新内容
        // 2. 直接在扩展内发起API请求拉取最新内容,系统给扩展预留的处理时间约30秒,足够普通接口响应
        BestAttemptContent.Title = "最新通知标题";
        BestAttemptContent.Body = "最新通知正文";
    }

    // 将修改后的内容回传给系统展示
    ContentHandler(BestAttemptContent);
}

public override void TimeWillExpire()
{
    // 系统分配的处理时间即将耗尽时,兜底返回现有内容,避免通知弹不出来
    ContentHandler(BestAttemptContent);
}

注意:通知服务扩展和主App是独立进程,不能直接读取主App内存中的数据,必须通过App Group共享容器或者独立网络请求获取数据。

3. 稳定的每日通知调度方案

不要使用系统UNCalendarNotificationTrigger自带的重复属性,这类重复通知的内容在创建时就被固化,无法动态更新。也不要只调度单条通知,避免某一次触发失败导致后续所有通知断链:

  • 采用滚动预调度方案,一次性预调度未来7-14天的每日通知,每个通知ID带上对应的日期后缀,比如DailyNotification_20240620
  • 每次App启动、回到前台、或者收到通知触发事件时,检查未来7-14天的通知调度队列,补齐缺失的通知即可
  • 预调度时通知内容可以先填占位符,触发时通过前面提到的两种替换逻辑换成最新内容即可

这种方案下,就算用户连续一周没打开App,提前调度好的通知也能正常触发,完全不会出现断链问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 10:15:33