Windows 推送通知服务 (WNS) 概述Windows Push Notification Services (WNS) overview

Windows 推送通知服务 (WNS) 使第三方开发人员可从自己的云服务发送 Toast、磁贴、锁屏提醒和原始更新。The Windows Push Notification Services (WNS) enables third-party developers to send toast, tile, badge, and raw updates from their own cloud service. 这提供了一种高效而可靠地向用户提供新更新的机制。This provides a mechanism to deliver new updates to your users in a power-efficient and dependable way.

工作原理How it works

下图显示了用于发送推送通知的完整数据流。The following diagram shows the complete data flow for sending a push notification. 它涉及到以下步骤:It involves these steps:

  1. 你的应用从通用 Windows 平台请求推送通知通道。Your app requests a push notification channel from the Universal Windows Platform.
  2. Windows 要求 WNS 创建通知通道。Windows asks WNS to create a notification channel. 此通道以统一资源标识符 (URI) 的形式返回到调用设备。This channel is returned to the calling device in the form of a Uniform Resource Identifier (URI).
  3. 通知通道 URI 由 Windows 返回到应用。The notification channel URI is returned by Windows to your app.
  4. 你的应用将 URI 发送到你自己的云服务。Your app sends the URI to your own cloud service. 然后你将 URI 存储在自己的云服务上,以便在发生通知时访问该 URI。You then store the URI on your own cloud service so that you can access the URI when you send notifications. URI 是你自己的应用与自己的服务之间的接口;它负责通过安全可靠的 Web 标准来实现此接口。The URI is an interface between your own app and your own service; it's your responsibility to implement this interface with safe and secure web standards.
  5. 当你的云服务有要发送的更新时,它使用通道 URI 通知 WNS。When your cloud service has an update to send, it notifies WNS using the channel URI. 通过安全套接字层 (SSL) 发送 TTP POST 请求(包括通知负载)来执行此操作。This is done by issuing an HTTP POST request, including the notification payload, over Secure Sockets Layer (SSL). 此步骤需要身份验证。This step requires authentication.
  6. WNS 接收请求,并将通知路由到相应的设备。WNS receives the request and routes the notification to the appropriate device.

推送通知的 WNS 数据流关系图

注册你的应用,并为你的云服务接收凭据Registering your app and receiving the credentials for your cloud service

在使用 WNS 发送通知之前,应用必须先向应用商店仪表板进行注册。Before you can send notifications using WNS, your app must be registered with the Store Dashboard. 这将为应用提供凭据,云服务在向 WNS 进行验证的过程中将使用该凭据。This will provide you with credentials for your app that your cloud service will use in authenticating with WNS. 这些凭据由程序包安全标识符 (SID) 和密钥组成。These credentials consist of a Package Security Identifier (SID) and a secret key. 若要执行此注册,登录到合作伙伴中心To perform this registration, sign in to Partner Center. 创建应用后,可以按照应用管理 - WNS/MPNS 页面上的说明检索凭证。After you create your app, you can retrieve the credentials by following the instructions on the App Management - WNS/MPNS page. 如果想使用 Live 服务解决方案,请访问此页面上的 Live 服务网站链接。If you want to use the Live Services solution, follow the Live services site link on this page.

每个应用都有其各自的一组云服务凭据。Each app has its own set of credentials for its cloud service. 这些凭据无法用于向其他任何应用发送通知。These credentials cannot be used to send notifications to any other app.

若要详细了解如何注册你的应用,请参阅如何向 Windows 通知服务 (WNS) 进行验证For more details on how to register your app, please see How to authenticate with the Windows Notification Service (WNS).

请求通知通道Requesting a notification channel

当能够接收推送通知的应用运行时,它必须首先通过 CreatePushNotificationChannelForApplicationAsync 请求通知通道。When an app that is capable of receiving push notifications runs, it must first request a notification channel through the CreatePushNotificationChannelForApplicationAsync. 若要查看全面介绍和示例代码,请参阅如何请求、创建和保存通知通道For a full discussion and example code, see How to request, create, and save a notification channel. 此 API 会返回一个唯一链接到进行调用的应用程序及其磁贴的通道 URI,所有通知类型均可通过此 URI 发送。This API returns a channel URI that is uniquely linked to the calling application and its tile, and through which all notification types can be sent.

应用成功创建了通道 URI 之后,会将其与任何应该与该 URI 关联的特定于应用的元数据一起发送到它的云服务。After the app has successfully created a channel URI, it sends it to its cloud service, together with any app-specific metadata that should be associated with this URI.

重要说明Important notes

  • 我们不保证应用的通知通道 URI 将始终保持相同。We do not guarantee that the notification channel URI for an app will always remain the same. 我们建议应用在每次运行时均请求一个新的通道,并在 URI 更改时更新其服务。We advise that the app requests a new channel every time it runs and updates its service when the URI changes. 开发人员绝不能修改该通道 URI,而应将其视作一段黑盒字符串。The developer should never modify the channel URI and should consider it as a black-box string. 此时,通道 URI 于 30 天后过期。At this time, channel URIs expire after 30 days. 如果 windows 10 应用会定期更新其通道在后台,你可以下载适用于 Windows8.1推送和定期通知示例并重新使用其源代码和/或它所演示的模式。If your Windows10 app will periodically renew its channel in the background then you can download the Push and periodic notifications sample for Windows8.1 and re-use its source code and/or the pattern it demonstrates.
  • 云服务和客户端应用之间的接口由你这个开发人员来实现。The interface between the cloud service and the client app is implemented by you, the developer. 我们建议应用使用其自身的服务完成身份验证过程,并通过安全的协议(如 HTTPS)来传输数据。We recommend that the app go through an authentication process with its own service and transmit data over a secure protocol such as HTTPS.
  • 云服务必须始终确保通道 URI 使用域“”。It is important that the cloud service always ensures that the channel URI uses the domain "". 该服务永远不应向任何其他域中的通道推送通知。The service should never push notifications to a channel on any other domain. 如果应用的回调发生了泄露,恶意攻击者可能会将该通道 URI 提交给假冒 WNS。If the callback for your app is ever compromised, a malicious attacker could submit a channel URI to spoof WNS. 如果不对域进行检查,你的云服务可能会在你不知情的情况下向此攻击者泄露信息。Without inspecting the domain, your cloud service could be potentially disclose information to this attacker unknowingly.
  • 如果你的云服务尝试将通知传递到过期通道,WNS 将返回响应代码 410If your cloud service attempts to deliver a notification to an expired channel, WNS will return response code 410. 为响应此代码,你的服务不应再尝试将通知发送到该 URI。In response to that code, your service should no longer attempt to send notifications to that URI.

验证你的云服务Authenticating your cloud service

若要发送通知,云服务必须通过 WNS 进行验证。To send a notification, the cloud service must be authenticated through WNS. 此过程的第一步出现在使用 Microsoft Store 仪表板注册应用之时。The first step in this process occurs when you register your app with the Microsoft Store Dashboard. 在注册过程中,应用会获得一个程序包安全标识符 (SID) 和一个密钥。During the registration process, your app is given a Package security identifier (SID) and a secret key. 该信息由你的云服务用于向 WNS 进行验证。This information is used by your cloud service to authenticate with WNS.

WNS 身份验证方案通过来自 OAuth 2.0 协议的客户端凭据配置文件来实现。The WNS authentication scheme is implemented using the client credentials profile from the OAuth 2.0 protocol. 云服务通过提供其凭据(程序包 SID 和密钥)来向 WNS 进行验证。The cloud service authenticates with WNS by providing its credentials (Package SID and secret key). 反过来,云服务会获得一个访问令牌。In return, it receives an access token. 该访问令牌允许云服务发送通知。This access token allows a cloud service to send a notification. 每次向 WNS 发送通知请求时都必须使用该令牌。The token is required with every notification request sent to the WNS.

该信息链简述如下:At a high level, the information chain is as follows:

  1. 云服务遵循 OAuth 2.0 协议通过 HTTPS 将其凭据发送给 WNS。The cloud service sends its credentials to WNS over HTTPS following the OAuth 2.0 protocol. 这会向 WNS 验证该服务。This authenticates the service with WNS.
  2. 如果身份验证成功,则 WNS 会返回一个访问令牌。WNS returns an access token if the authentication was successful. 此访问令牌在所有后续通知请求中使用,直到令牌过期。This access token is used in all subsequent notification requests until it expires.

云服务身份验证的 WNS 关系图

在对 WNS 进行身份验证的过程中,云服务会通过安全套接字层 (SSL) 提交一个 HTTP 请求。In the authentication with WNS, the cloud service submits an HTTP request over Secure Sockets Layer (SSL). 参数以“application/x-www-for-urlencoded”格式提供。The parameters are supplied in the "application/x-www-for-urlencoded" format. 在“client_id”字段中提供你的程序包 SID,并在“client_secret”字段中提供你的密钥。Supply your Package SID in the "client_id" field and your secret key in the "client_secret" field. 有关语法的详细信息,请参阅访问令牌请求参考。For syntax details, see the access token request reference.

注意这是只是一个示例中,你可以在自己的代码中成功使用的不剪切和粘贴代码。NoteThis is just an example, not cut-and-paste code that you can successfully use in your own code.

 POST /accesstoken.srf HTTP/1.1
 Content-Type: application/x-www-form-urlencoded
 Content-Length: 211


WNS 对云服务进行身份验证,如果成功,则发送“200 OK”响应。The WNS authenticates the cloud service and, if successful, sends a response of "200 OK". 访问令牌使用“application/json”媒体类型在该 HTTP 响应正文所含的参数中返回。The access token is returned in the parameters included in the body of the HTTP response, using the "application/json" media type. 在你的服务收到该访问令牌后,可随时开始发送通知。After your service has received the access token, you are ready to send notifications.

以下示例将显示一个包含访问令牌身份的成功验证响应。The following example shows a successful authentication response, including the access token. 有关语法的详细信息,请参阅推送通知服务请求和响应头For syntax details, see Push notification service request and response headers.

 HTTP/1.1 200 OK   
 Cache-Control: no-store
 Content-Length: 422
 Content-Type: application/json


重要说明Important notes

  • 以上过程支持的 OAuth 2.0 协议遵循草案版本 V16。The OAuth 2.0 protocol supported in this procedure follows draft version V16.
  • OAuth 征求意见文档 (RFC) 使用术语“客户端”指示云服务。The OAuth Request for Comments (RFC) uses the term "client" to refer to the cloud service.
  • 当该 OAuth 草案定稿时,以上过程可能有所更改。There might be changes to this procedure when the OAuth draft is finalized.
  • 访问令牌可用于多个通知请求。The access token can be reused for multiple notification requests. 这样,云服务只需验证一次即可发送多个通知。This allows the cloud service to authenticate just once to send many notifications. 然而,当访问令牌过期时,云服务必须再次验证,以获得一个新的访问令牌。However, when the access token expires, the cloud service must authenticate again to receive a new access token.

发送通知Sending a notification

通过使用通道 URI,无论何时有适用于客户的更新,云服务都可以发送通知。Using the channel URI, the cloud service can send a notification whenever it has an update for the user.

上述访问令牌可用于多个通知请求;云服务不必为每个通知都请求一个新的访问令牌。The access token described above can be reused for multiple notification requests; the cloud server is not required to request a new access token for every notification. 如果访问令牌过期,通知请求将返回一个错误。If the access token has expired, the notification request will return an error. 如果访问令牌被拒绝,我们建议你不要尝试多次重新发送通知。We recommended that you do not try to re-send your notification more than once if the access token is rejected. 如果遇到该错误,你将需要请求一个新的访问令牌并重新发送通知。If you encounter this error, you will need to request a new access token and resend the notification. 有关准确的错误代码,请参阅推送通知响应代码For the exact error code, see Push notification response codes.

  1. 云服务会向通道 URI 发出一个 HTTP POST。The cloud service makes an HTTP POST to the channel URI. 该请求必须通过 SSL 发出并包含必要的标头和通知负载。This request must be made over SSL and contains the necessary headers and the notification payload. 授权头必须包含授权所必需的访问令牌。The authorization header must include the acquired access token for authorization.

    示例请求如下。An example request is shown here. 有关语法的详细信息,请参阅推送通知响应代码For syntax details, see Push notification response codes.

    有关编写通知负载的详细信息,请参阅快速入门:发送推送通知For details on composing the notification payload, see Quickstart: Sending a push notification. 磁贴、Toast 或锁屏提醒通知的负载作为 XML 内容提供,并依附于其分别定义的适应磁贴架构传统磁贴架构The payload of a tile, toast, or badge push notification is supplied as XML content that adheres to their respective defined Adaptive tiles schema or Legacy tiles schema. 原始通知的负载没有指定的结构。The payload of a raw notification does not have a specified structure. 严格来讲它是由应用定义的。It is strictly app-defined.

     POST HTTP/1.1
     Content-Type: text/xml
     X-WNS-Type: wns/tile
     Authorization: Bearer EgAcAQMAAAAALYAAY/c+Huwi3Fv4Ck10UrKNmtxRO6Njk2MgA=
     Content-Length: 24
  2. WNS 发出响应,表明通知已收到,并将在下次可能时传递。WNS responds to indicate that the notification has been received and will be delivered at the next available opportunity. 但是,WNS 不会提供设备或应用程序已收到通知的端到端确认。However, WNS does not provide end-to-end confirmation that your notification has been received by the device or application.

此关系图演示数据流:This diagram illustrates the data flow:

发送通知的 WNS 关系图

重要说明Important notes

  • WNS 不保证通知的可靠性或延迟。WNS does not guarantee the reliability or latency of a notification.
  • 通知绝不应包含机密或敏感数据。Notifications should never include confidential or sensitive data.
  • 若要发送通知,云服务必须先对 WNS 进行身份验证并获得访问令牌。To send a notification, the cloud service must first authenticate with WNS and receive an access token.
  • 访问令牌仅允许云服务将通知发送到为其创建令牌的单个应用。An access token only allows a cloud service to send notifications to the single app for which the token was created. 单个访问令牌无法用于在多个应用中发送通知。One access token cannot be used to send notifications across multiple apps. 因此,如果你的云服务支持多个应用,则在向每个通道 URI 推送通知时都必须提供相应应用的正确访问令牌。Therefore, if your cloud service supports multiple apps, it must provide the correct access token for the app when pushing a notification to each channel URI.
  • 当设备脱机时,WNS 将默认为每个通道 URI 存储至多 5 个磁贴通知(如果启用了队列;否则只能存储 1 个磁贴通知)和 1 个锁屏提醒通知,不存储原始通知。When the device is offline, by default WNS will store up to five tile notifications (if queuing is enabled; otherwise, one tile notification) and one badge notification for each channel URI, and no raw notifications. 可以通过 X-WNS-Cache-Policy 标头更改这种默认缓存行为。This default caching behavior can be changed through the X-WNS-Cache-Policy header. 请注意,当设备离线时,永远不会存储 Toast 通知。Note that toast notifications are never stored when the device is offline.
  • 在对用户个性化通知内容的方案中,WNS 建议云服务在收到这些更新时立即发送这些更新。In scenarios where the notification content is personalized to the user, WNS recommends that the cloud service immediately send those updates when those are received. 此方案的示例包括社交媒体源更新、即时通信邀请、新消息通知或警报。Examples of this scenario include social media feed updates, instant communication invitations, new message notifications, or alerts. 作为备用方法,你可以使用向大部分用户频繁提供相同的通用更新的方案;例如,天气、股票和新闻更新。As an alternative, you can have scenarios in which the same generic update is frequently delivered to a large subset of your users; for example, weather, stock, and news updates. WNS 指南中指定这些更新的频率最高为每 30 分钟一个。WNS guidelines specify that the frequency of these updates should be at most one every 30 minutes. 最终用户或 WNS 可以将超过该频率的例常更新确定为滥发更新。The end user or WNS may determine more frequent routine updates to be abusive.

磁贴和锁屏提醒通知过期时间Expiration of tile and badge notifications

默认情况下,磁贴和徽标通知在下载完成时的三天后过期。By default, tile and badge notifications expire three days after being downloaded. 通知过期时,此内容将从磁贴或队列中删除,且不再向用户显示。When a notification expires, the content is removed from the tile or queue and is no longer shown to the user. 最佳做法是在所有磁贴和锁屏提醒通知上设置过期时间(使用对你的应用有意义的时间),以便使磁贴的内容不会在它不相关时继续保留。It's a best practice to set an expiration (using a time that makes sense for your app) on all tile and badge notifications so that your tile's content doesn't persist longer than it is relevant. 对于具有已定义的使用寿命的内容来说,显式过期时间是必需的。An explicit expiration time is essential for content with a defined lifespan. 这还确保在你的云服务停止发送通知或用户在长时间内与网络断开连接时删除过时的内容。This also assures the removal of stale content if your cloud service stops sending notifications, or if the user disconnects from the network for an extended period.

你的云服务可以为每个通知设置一个过期时间,方法是设置 X-WNS-TTL HTTP 标头以指定通知在发送后保持有效的时间(以秒为单位)。Your cloud service can set an expiration for each notification by setting the X-WNS-TTL HTTP header to specify the time (in seconds) that your notification will remain valid after it is sent. 有关详细信息,请参阅推送通知服务请求和响应头For more information, see Push notification service request and response headers.

例如,股票市场活跃交易日期间,你可将股票价格更新到期时间设置为发送间隔的两倍(例如,如果是每半小时发送一次通知,则将股票价格更新到期时间设置为一小时)。For example, during a stock market's active trading day, you can set the expiration for a stock price update to twice that of your sending interval (such as one hour after receipt if you are sending notifications every half-hour). 另一个示例是,新闻应用可确定每日新闻磁贴更新的适当到期时间为一天。As another example, a news app might determine that one day is an appropriate expiration time for a daily news tile update.

推送通知和节电模式Push notifications and battery saver

节电模式可通过限制设备上的后台活动,延长电池使用时间。Battery saver extends battery life by limiting background activity on the device. Windows 10 允许用户设置节电模式电池电量低于指定的阈值时自动打开。Windows10 lets the user set battery saver to turn on automatically when the battery drops below a specified threshold. 在节电模式处于打开状态时,将禁用推送消息接收,以节省电量。When battery saver is on, the receipt of push notifications is disabled to save energy. 但是也有几种例外情况。But there are a couple exceptions to this. 以下 windows 10 节电模式设置 (设置应用中找到) 允许应用接收推送通知,即使节电模式打开。The following Windows10 battery saver settings (found in the Settings app) allow your app to receive push notifications even when battery saver is on.

  • 允许在节电模式下接收任何应用的推送通知:此设置允许所有应用在节电模式处于打开状态时接收推送通知。Allow push notifications from any app while in battery saver: This setting lets all apps receive push notifications while battery saver is on. 请注意,此设置仅适用于 windows 10 桌面版 (家庭版、 专业版、 企业版和教育版)。Note that this setting applies only to Windows10 for desktop editions (Home, Pro, Enterprise, and Education).
  • 始终允许:此设置允许在节电模式处于打开状态时在后台运行特定应用,包括接收推送通知。Always allowed: This setting lets specific apps run in the background while battery saver is on - including receiving push notifications. 此列表由用户手动维护。This list is maintained manually by the user.

此两种设置的状态无法检查,但可以检查节电模式的状态。There is no way to check the state of these two settings, but you can check the state of battery saver. 在 windows 10,使用EnergySaverStatus属性检查节电模式状态。In Windows10, use the EnergySaverStatus property to check battery saver state. 应用也可以使用 EnergySaverStatusChanged 事件侦听对节电模式的更改。Your app can also use the EnergySaverStatusChanged event to listen for changes to battery saver.

如果应用严重依赖推送通知,我们建议通知用户,在节电模式打开时,他们可能无法接收通知,并让他们可以轻松地调整节电模式设置If your app depends heavily on push notifications, we recommend notifying users that they may not receive notifications while battery saver is on and to make it easy for them to adjust battery saver settings. 在 windows 10,使用节电模式设置 URI 架构ms-settings:batterysaver-settings,你可以提供指向设置应用的简便链接。Using the battery saver settings URI scheme in Windows10, ms-settings:batterysaver-settings, you can provide a convenient link to the Settings app.

提示时通知用户有关节电模式设置,我们建议提供在未来阻止消息的方法。Tip When notifying the user about battery saver settings, we recommend providing a way to suppress the message in the future. 例如,以下示例中的 dontAskMeAgainBox 复选框保留用户在 LocalSettings 中的首选项。For example, the dontAskMeAgainBox checkbox in the following example persists the user's preference in LocalSettings.

下面是如何检查节电模式在 windows 10 中打开的示例。Here's an example of how to check if battery saver is turned on in Windows10. 此示例将通知用户,并将“设置”应用启动到节电模式设置This example notifies the user and launches the Settings app to battery saver settings. dontAskAgainSetting 允许用户在不希望再次收到通知时阻止消息。The dontAskAgainSetting lets the user suppress the message if they don't want to be notified again.

using System;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;
using Windows.System;
using Windows.System.Power;
async public void CheckForEnergySaving()
   //Get reminder preference from LocalSettings
   bool dontAskAgain;
   var localSettings = Windows.Storage.ApplicationData.Current.LocalSettings;
   object dontAskSetting = localSettings.Values["dontAskAgainSetting"];
   if (dontAskSetting == null)
   {  // Setting does not exist
      dontAskAgain = false;
   {  // Retrieve setting value
      dontAskAgain = Convert.ToBoolean(dontAskSetting);

   // Check if battery saver is on and that it's okay to raise dialog
   if ((PowerManager.EnergySaverStatus == EnergySaverStatus.On)
         && (dontAskAgain == false))
      // Check dialog results
      ContentDialogResult dialogResult = await saveEnergyDialog.ShowAsync();
      if (dialogResult == ContentDialogResult.Primary)
         // Launch battery saver settings (settings are available only when a battery is present)
         await Launcher.LaunchUriAsync(new Uri("ms-settings:batterysaver-settings"));

      // Save reminder preference
      if (dontAskAgainBox.IsChecked == true)
      {  // Don't raise dialog again
         localSettings.Values["dontAskAgainSetting"] = "true";

这是适用于此示例中重点介绍的 ContentDialog 的 XAML。This is the XAML for the ContentDialog featured in this example.

<ContentDialog x:Name="saveEnergyDialog"
               PrimaryButtonText="Open battery saver settings"
               Title="Battery saver is on."> 
      <TextBlock TextWrapping="WrapWholeWords">
         <LineBreak/><Run>Battery saver is on and you may 
          not receive push notifications.</Run><LineBreak/>
         <LineBreak/><Run>You can choose to allow this app to work normally
         while in battery saver, including receiving push notifications.</Run>
      <CheckBox x:Name="dontAskAgainBox" Content="OK, got it."/>