从 UWP 应用发送本地 toast 通知Send a local toast notification from UWP apps

Toast 通知是用户当前未在应用内部时应用可构造并发送给用户的消息。A toast notification is a message that an app can construct and deliver to the user while they are not currently inside your app. 此快速入门指南将指导你借助新自适应模板和交互式操作完成创建、交付并显示 Windows 10 toast 通知的步骤。This Quickstart walks you through the steps to create, deliver, and display a Windows 10 toast notification with the new adaptive templates and interactive actions. 通过本地通知对这些操作进行说明,本地通知是实现起来最简单的通知。These actions are demonstrated through a local notification, which is the simplest notification to implement.

重要

桌面应用程序 (包括打包的 .msix 应用、使用 稀疏包 获取包标识的应用,以及经典非打包桌面应用) 执行发送通知和处理激活的步骤不同。Desktop applications (including packaged MSIX apps, apps that use sparse packages to obtain package identity, and classic non-packaged Desktop apps) have different steps for sending notifications and handling activation. 请参阅桌面 app 文档,了解如何实现 toast。Please see the Desktop apps documentation to learn how to implement toasts.

重要 APIToastNotification 类ToastNotificationActivatedEventArgs 类Important APIs: ToastNotification Class, ToastNotificationActivatedEventArgs Class

步骤1:安装 NuGet 包Step 1: Install NuGet package

安装 "..." NuGet 包Install the Microsoft.Toolkit.Uwp.Notifications NuGet package. 我们的代码示例将使用此包。Our code sample will use this package. 本文结束时,我们会提供不使用任何 NuGet 包的 "纯" 代码片段。At the end of the article we'll provide the "plain" code snippets that don't use any NuGet packages. 使用此包可以创建 toast 通知,而无需使用 XML。This package allows you to create toast notifications without using XML.

步骤2:添加命名空间声明Step 2: Add namespace declarations

Windows.UI.Notifications 包括 toast Api。Windows.UI.Notifications includes the toast APIs.

using Windows.UI.Notifications;
using Microsoft.Toolkit.Uwp.Notifications; // Notifications library

步骤3:发送 toastStep 3: Send a toast

在 Windows 10 中,你的 toast 通知内容是使用对于你的通知外观给予了最大程度灵活性的自适应语言描述的。In Windows 10, your toast notification content is described using an adaptive language that allows great flexibility with how your notification looks. 有关详细信息,请参阅 toast 内容文档See the toast content documentation for more information.

我们将从一个简单的基于文本的通知开始。We'll start with a simple text-based notification. 使用通知库) 构造通知内容 (并显示通知!Construct the notification content (using the Notifications library), and show the notification!

Simple text notification
// Construct the content
var content = new ToastContentBuilder()
    .AddToastActivationInfo("picOfHappyCanyon", ToastActivationType.Foreground)
    .AddText("Andrew sent you a picture")
    .AddText("Check this out, Happy Canyon in Utah!")
    .GetToastContent();

// Create the notification
var notif = new ToastNotification(content.GetXml());

// And show it!
ToastNotificationManager.CreateToastNotifier().Show(notif);

步骤4:处理激活Step 4: Handling activation

当用户单击你的通知 (或使用前台激活) 通知上的按钮时,将调用应用的 App.xaml.cs OnActivatedWhen the user clicks your notification (or a button on the notification with foreground activation), your app's App.xaml.cs OnActivated will be invoked.

App.xaml.csApp.xaml.cs

protected override void OnActivated(IActivatedEventArgs e)
{
    // Handle notification activation
    if (e is ToastNotificationActivatedEventArgs toastActivationArgs)
    {
        // Obtain the arguments from the notification
        string args = toastActivationArgs.Argument;

        // Obtain any user input (text boxes, menu selections) from the notification
        ValueSet userInput = toastActivationArgs.UserInput;
 
        // TODO: Show the corresponding content
    }
}

重要

必须按 OnLaunched 代码那样初始化框架和激活窗口。You must initialize your frame and activate your window just like your OnLaunched code. 如果用户单击你的 toast ,则不会调用 OnLaunched,即使你的应用已关闭并是首次启动也是如此。OnLaunched is NOT called if the user clicks on your toast, even if your app was closed and is launching for the first time. 通常建议将 OnLaunchedOnActivated 合并到你自己的 OnLaunchedOrActivated 方法中,因为二者中均需执行相同的初始化。We often recommend combining OnLaunched and OnActivated into your own OnLaunchedOrActivated method since the same initialization needs to occur in both.

深度激活Activation in depth

使你的通知可操作的第一步是将一些启动参数添加到你的通知,以便你的应用程序可以知道当用户单击通知时要启动的内容 (在这种情况下,我们将包括一些信息,稍后会告诉我们你应该打开一个会话,并且我们知道要打开哪些特定对话) 。The first step in making your notifications actionable is to add some launch args to your notification, so that your app can know what to launch when the user clicks the notification (in this case, we're including some information that later tells us we should open a conversation, and we know which specific conversation to open).

建议安装 QueryString.NET NuGet 包,以帮助构造和分析通知参数的查询字符串,如下所示。We recommend installing the QueryString.NET NuGet package to help construct and parse query strings for your notification arguments, as seen below.

using Microsoft.QueryStringDotNET; // QueryString.NET

int conversationId = 384928;

// Construct the content
var content = new ToastContentBuilder()

    // Arguments returned when user taps body of notification
    .AddToastActivationInfo(new QueryString() // Using QueryString.NET
    {
        { "action", "viewConversation" },
        { "conversationId", conversationId.ToString() }
    }.ToString(), ToastActivationType.Foreground)

    .AddText("Andrew sent you a picture")
    ...

下面是一个更复杂的示例,说明如何处理激活 .。。Here's a more complex example of handling activation...

App.xaml.csApp.xaml.cs

protected override void OnActivated(IActivatedEventArgs e)
{
    // Get the root frame
    Frame rootFrame = Window.Current.Content as Frame;
 
    // TODO: Initialize root frame just like in OnLaunched
 
    // Handle toast activation
    if (e is ToastNotificationActivatedEventArgs toastActivationArgs)
    {            
        // Parse the query string (using QueryString.NET)
        QueryString args = QueryString.Parse(toastActivationArgs.Argument);
 
        // See what action is being requested 
        switch (args["action"])
        {
            // Open the image
            case "viewImage":
 
                // The URL retrieved from the toast args
                string imageUrl = args["imageUrl"];
 
                // If we're already viewing that image, do nothing
                if (rootFrame.Content is ImagePage && (rootFrame.Content as ImagePage).ImageUrl.Equals(imageUrl))
                    break;
 
                // Otherwise navigate to view it
                rootFrame.Navigate(typeof(ImagePage), imageUrl);
                break;
                             
 
            // Open the conversation
            case "viewConversation":
 
                // The conversation ID retrieved from the toast args
                int conversationId = int.Parse(args["conversationId"]);
 
                // If we're already viewing that conversation, do nothing
                if (rootFrame.Content is ConversationPage && (rootFrame.Content as ConversationPage).ConversationId == conversationId)
                    break;
 
                // Otherwise navigate to view it
                rootFrame.Navigate(typeof(ConversationPage), conversationId);
                break;
        }
 
        // If we're loading the app for the first time, place the main page on
        // the back stack so that user can go back after they've been
        // navigated to the specific page
        if (rootFrame.BackStack.Count == 0)
            rootFrame.BackStack.Add(new PageStackEntry(typeof(MainPage), null, null));
    }
 
    // TODO: Handle other types of activation
 
    // Ensure the current window is active
    Window.Current.Activate();
}

添加图像Adding images

可以向通知添加丰富的内容。You can add rich content to notifications. 我们会将一个内联图像和一个配置文件 (应用徽标覆盖) 映像。We'll add an inline image and a profile (app logo override) image.

备注

图像可来自于应用包、应用的本地存储或来自 Web。Images can be used from the app's package, the app's local storage, or from the web. 自 Fall Creators Update 起,正常连接上的 Web 图像的大小限制提升至 3 MB,按流量计费的连接上的限制提升至 1 MB。As of the Fall Creators Update, web images can be up to 3 MB on normal connections and 1 MB on metered connections. 在尚未运行 Fall Creators Update 的设备上,Web 图像的大小不得超过 200 KB。On devices not yet running the Fall Creators Update, web images must be no larger than 200 KB.

重要

Http 映像仅在其清单中具有 internet 功能的 UWP/.MSIX/稀疏应用中受支持。Http images are only supported in UWP/MSIX/sparse apps that have the internet capability in their manifest. 桌面非 .MSIX/稀疏应用不支持 http 映像;必须将映像下载到本地应用数据,并在本地引用它。Desktop non-MSIX/sparse apps do not support http images; you must download the image to your local app data and reference it locally.

Toast with images
// Construct the content
var content = new ToastContentBuilder()
    ...

    // Inline image
    .AddInlineImage(new Uri("https://picsum.photos/360/202?image=883"))

    // Profile (app logo override) image
    .AddAppLogoOverride(new Uri("ms-appdata:///local/Andrew.jpg"), ToastGenericAppLogoCrop.Circle)
    
    .GetToastContent();
    
...

添加按钮和输入Adding buttons and inputs

你可以添加按钮和输入以使你的通知交互。You can add buttons and inputs to make your notifications interactive. 按钮可以启动前景应用、协议或后台任务。Buttons can launch your foreground app, a protocol, or your background task. 我们将添加一个 "答复" 文本框、一个 "赞" 按钮和一个打开该图像的 "视图" 按钮。We'll add a reply text box, a "Like" button, and a "View" button that opens the image.

Toast with images and buttons
int conversationId = 384928;

// Construct the content
var content = new ToastContentBuilder()
    ...

    // Text box for replying
    .AddInputTextBox("tbReply", placeHolderContent: "Type a response")

    // Reference the text box's ID in order to place this button next to the text box
    .AddButton("tbReply", "Reply", ToastActivationType.Background, new QueryString()
    {
        { "action", "reply" },
        { "conversationId", conversationId.ToString() }
    }.ToString(), imageUri: new Uri("Assets/Reply.png", UriKind.Relative))

    .AddButton("Like", ToastActivationType.Background, new QueryString()
    {
        { "action", "like" },
        { "conversationId", conversationId.ToString() }
    }.ToString())

    .AddButton("View", ToastActivationType.Foreground, new QueryString()
    {
        { "action", "viewImage" },
        { "imageUrl", image.ToString() }
    }.ToString())
    
    .GetToastContent();
    
...

将按照与主 toast 正文相同的方式来处理前景按钮的激活方式, (App.xaml.cs OnActivated 将被称为) 。The activation of foreground buttons are handled in the same way as the main toast body (your App.xaml.cs OnActivated will be called).

处理后台激活Handling background activation

当你对你的 toast(或 toast 内的按钮)指定后台激活时,将执行后台任务而不是激活前台应用。When you specify background activation on your toast (or on a button inside the toast), your background task will be executed instead of activating your foreground app.

有关后台任务的详细信息,请参阅使用后台任务支持应用For more information on background tasks, please see Support your app with background tasks.

如果你的目标版本是 14393 或更高版本,则可以使用进程内后台任务,这样可大大简化操作。If you are targeting build 14393 or higher, you can use in-process background tasks, which greatly simplify things. 请注意,无法在较旧版本的 Windows 上运行进程内后台任务。Note that in-process background tasks will fail to run on older versions of Windows. 在此代码示例中,将使用进程内后台任务。We'll use an in-process background task in this code sample.

const string taskName = "ToastBackgroundTask";

// If background task is already registered, do nothing
if (BackgroundTaskRegistration.AllTasks.Any(i => i.Value.Name.Equals(taskName)))
    return;

// Otherwise request access
BackgroundAccessStatus status = await BackgroundExecutionManager.RequestAccessAsync();

// Create the background task
BackgroundTaskBuilder builder = new BackgroundTaskBuilder()
{
    Name = taskName
};

// Assign the toast action trigger
builder.SetTrigger(new ToastNotificationActionTrigger());

// And register the task
BackgroundTaskRegistration registration = builder.Register();

然后在 App.xaml.cs 中,重写 OnBackgroundActivated 方法。Then in your App.xaml.cs, override the OnBackgroundActivated method. 然后,你可以检索预定义参数和用户输入,类似于前台激活。You can then retrieve the pre-defined arguments and user input, similar to the foreground activation.

App.xaml.csApp.xaml.cs

protected override async void OnBackgroundActivated(BackgroundActivatedEventArgs args)
{
    var deferral = args.TaskInstance.GetDeferral();
 
    switch (args.TaskInstance.Task.Name)
    {
        case "ToastBackgroundTask":
            var details = args.TaskInstance.TriggerDetails as ToastNotificationActionTriggerDetail;
            if (details != null)
            {
                string arguments = details.Argument;
                var userInput = details.UserInput;

                // Perform tasks
            }
            break;
    }
 
    deferral.Complete();
}

设置过期时间Set an expiration time

在 Windows 10 中,所有 toast 通知被用户消除或忽略后将转到操作中心,以便在弹出窗口消失后,用户仍可查看通知。In Windows 10, all toast notifications go in Action Center after they are dismissed or ignored by the user, so users can look at your notification after the popup is gone.

但是,如果你的通知中的消息仅在一段时间内相关,则应对 toast 通知设置过期时间,让用户不至于看到来自应用的过时信息。However, if the message in your notification is only relevant for a period of time, you should set an expiration time on the toast notification so the users do not see stale information from your app. 例如,如果升级的有效时间仅为 12 个小时,则将过期时间设置为 12 个小时。For example, if a promotion is only valid for 12 hours, set the expiration time to 12 hours. 下面的代码中将过期时间设置为 2 天。In the code below, we set the expiration time to be 2 days.

备注

本地 toast 通知的默认和最长过期时间为 3 天。The default and maximum expiration time for local toast notifications is 3 days.

// Create toast content
var content = new ToastContentBuilder()
    .AddText("Expires in 2 days...")
    .GetToastContent();

// Set expiration time
var notif = new ToastNotification(content.GetXml())
{
    ExpirationTime = DateTime.Now.AddDays(2)
};

// And show it!
ToastNotificationManager.CreateToastNotifier().Show(notif);

为 toast 提供主键Provide a primary key for your toast

如要以编程方式删除或替换发送的通知,需使用 Tag 属性(还可选择使用 Group 属性)来为通知提供主键。If you want to programmatically remove or replace the notification you send, you need to use the Tag property (and optionally the Group property) to provide a primary key for your notification. 然后,你可以在以后使用此主键来删除或替换该通知。Then, you can use this primary key in the future to remove or replace the notification.

要查看有关替换/删除已发送的 toast 通知的更多详细信息,请参阅快速入门:在操作中心 (XAML) 中管理 toast 通知To see more details on replacing/removing already delivered toast notifications, please see Quickstart: Managing toast notifications in action center (XAML).

Tag 和 Group 组合充当复合主键。Tag and Group combined act as a composite primary key. Group 是两者中较为通用的标识符,你可以用它来分配如“wallPosts”、“messages”、“friendRequests”等组。而 Tag 应该唯一标识组中的通知本身。Group is the more generic identifier, where you can assign groups like "wallPosts", "messages", "friendRequests", etc. And then Tag should uniquely identify the notification itself from within the group. 使用通用组时,可以使用 RemoveGroup API 删除该组中的所有通知。By using a generic group, you can then remove all notifications from that group by using the RemoveGroup API.

// Create toast content
var content = new ToastContentBuilder()
    .AddText("New post on your wall!")
    .GetToastContent();

// Set tag/group
new ToastNotification(content.GetXml())
{
    Tag = "18365",
    Group = "wallPosts"
};

// And show it!
ToastNotificationManager.CreateToastNotifier().Show(notif);

清除你的通知Clear your notifications

UWP 应用负责删除和清除它们自己的通知。UWP apps are responsible for removing and clearing their own notifications. 当你的应用启动时,我们不会自动清除你的通知。When your app is launched, we do NOT automatically clear your notifications.

仅当用户显式单击通知时,Windows 才会自动删除该通知。Windows will only automatically remove a notification if the user explicitly clicks the notification.

下面是消息传递应用应执行的操作的示例...Here's an example of what a messaging app should do…

  1. 用户收到关于对话中新消息的多个 toastUser receives multiple toasts about new messages in a conversation
  2. 用户点击其中一个 toast 以打开该对话User taps one of those toasts to open the conversation
  3. 应用打开该对话,然后清除该对话的所有 toast(方法是对该对话的应用提供的组使用 RemoveGroupThe app opens the conversation and then clears all toasts for that conversation (by using RemoveGroup on the app-supplied group for that conversation)
  4. 用户的操作中心现在能正确反映通知状态,因为操作中心未留有该对话的过期通知。User's Action Center now properly reflects the notification state, since there are no stale notifications for that conversation left in Action Center.

若要了解有关清除所有通知或删除特定通知的信息,请参阅快速入门:在操作中心 (XAML) 中管理 toast 通知To learn about clearing all notifications or removing specific notifications, see Quickstart: Managing toast notifications in action center (XAML).

ToastNotificationManager.History.Clear();

普通代码片段Plain code snippets

如果使用的不是 NuGet 中的通知库,可以按如下所示手动构造 XML,以创建 ToastNotificationIf you're not using the Notifications library from NuGet, you can manually construct your XML as seen below to create a ToastNotification.

using Windows.UI.Notifications;
using Windows.Data.Xml.Dom;

// In a real app, these would be initialized with actual data
string title = "Andrew sent you a picture";
string content = "Check this out, Happy Canyon in Utah!";
string image = "http://blogs.msdn.com/cfs-filesystemfile.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-71-81-permanent/2727.happycanyon1_5B00_1_5D00_.jpg";
string logo = "ms-appdata:///local/Andrew.jpg";
 
// TODO: all values need to be XML escaped
 
// Construct the visuals of the toast
string toastVisual =
$@"<visual>
  <binding template='ToastGeneric'>
    <text>{title}</text>
    <text>{content}</text>
    <image src='{image}'/>
    <image src='{logo}' placement='appLogoOverride' hint-crop='circle'/>
  </binding>
</visual>";

// In a real app, these would be initialized with actual data
int conversationId = 384928;
 
// Generate the arguments we'll be passing in the toast
string argsReply = $"action=reply&conversationId={conversationId}";
string argsLike = $"action=like&conversationId={conversationId}";
string argsView = $"action=viewImage&imageUrl={Uri.EscapeDataString(image)}";
 
// TODO: all args need to be XML escaped
 
string toastActions =
$@"<actions>
 
  <input
      type='text'
      id='tbReply'
      placeHolderContent='Type a response'/>
 
  <action
      content='Reply'
      arguments='{argsReply}'
      activationType='background'
      imageUri='Assets/Reply.png'
      hint-inputId='tbReply'/>
 
  <action
      content='Like'
      arguments='{argsLike}'
      activationType='background'/>
 
  <action
      content='View'
      arguments='{argsView}'/>
 
</actions>";

// Now we can construct the final toast content
string argsLaunch = $"action=viewConversation&conversationId={conversationId}";
 
// TODO: all args need to be XML escaped
 
string toastXmlString =
$@"<toast launch='{argsLaunch}'>
    {toastVisual}
    {toastActions}
</toast>";
 
// Parse to XML
XmlDocument toastXml = new XmlDocument();
toastXml.LoadXml(toastXmlString);
 
// Generate toast
var toast = new ToastNotification(toastXml);

资源Resources