背水一战 Windows 10 (121) - 后台任务: 推送通知

[源码下载]

作者:webabcd

介绍
背水一战 Windows 10 之 后台任务

  • 推送通知

示例
演示如何接收推送通知
/WebApi/PushNotificationController.cs

/*
 * 演示如何向 app 推送通知
 * 由于本例没有上商店,所以本例是无法演示的,需要看演示效果的话运行一下自己写的“打字通”的 /TypingGame/PushNotification/Sample.xaml,然后用其生成的 channel 地址在 /WebApi/Controllers/PushNotificationController.cs 推送通知
 *
 *
 * 注:
 * 关于推送通知服务请求和响应头的详细说明参见:https://msdn.microsoft.com/zh-cn/library/windows/apps/hh465435.aspx
 */

using System;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Web.Http;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
using System.Threading.Tasks;

namespace WebApi.Controllers
{
    public class PushNotificationController : ApiController
    {
        [HttpGet]
        public async Task<HttpResponseMessage> Get()
        {
            // 向某个 app 推送通知的 channel 地址(通过客户端的 PushNotificationChannelManager.CreatePushNotificationChannelForApplicationAsync() 方法生成)
            string notifyUrl = "https://hk2.notify.windows.com/?token=AwYAAAANZzLsCX%2fl1aavCSQhi%2fdEBO5wdplj7S4a3o4t8wGSGo05hRE6VC7xEMCFtGDrVuV%2f9J2ItuVri1F4Z0YNjtbuCqf6LQvov0UE3%2flD1sP1poaS1Qp30UQ%2fWVKVUBCjPFuWFLuyuq7UuuTvJcCcQzey";

            // 在商店后台的 dashboard 中的“Package SID”中可以找到此值(可以在 https://apps.dev.microsoft.com/ 中查找)
            string sid = "ms-app://s-1-15-2-1792688850-3283391166-**********-**********-**********-1809961044-230289451";
            // 在商店后台的 dashboard 中的“Application Secrets”中可以找到此值(可以在 https://apps.dev.microsoft.com/ 中查找)
            string secret = "koghs4zz*************S+5sEoqoNb4";

            OAuthHelper oAuth = new OAuthHelper();
            OAuthToken token = oAuth.GetAccessToken(secret, sid);

            HttpResponseMessage result = null;

            try
            {
                HttpClient httpClient = new HttpClient();
                HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, notifyUrl);

                // 推送消息的类型:wns/toast | wns/badge | wns/tile | wns/raw
                request.Headers.Add("X-WNS-Type", "wns/toast");
                // 设置 access-token
                request.Headers.Add("Authorization", String.Format("Bearer {0}", token.AccessToken));

                // 需要推送的 toast 通知的内容
                string toastXml = $@"
                    <toast activationType=‘foreground‘ launch=‘PushNotification-Toast-Arguments‘>
                        <visual>
                            <binding template=‘ToastGeneric‘>
                                <text>toast - title</text>
                                <text>toast - content {DateTime.Now.ToString("mm:ss")}</text>
                            </binding>
                        </visual>
                    </toast>";

                // toast, tile, badge 为 text/xml; raw 为 application/octet-stream
                request.Content = new StringContent(toastXml, Encoding.UTF8, "text/xml");

                HttpResponseMessage response = await httpClient.SendAsync(request);
                /*
                 * 响应代码说明
                 *     200 - OK,WNS 已接收到通知
                 *     400 - 错误的请求
                 *     401 - 未授权,token 可能无效
                 *     403 - 已禁止,manifest 中的 identity 可能不对
                 *     404 - 未找到
                 *     405 - 方法不允许
                 *     406 - 无法接受
                 *     410 - 不存在,信道不存在或过期
                 *     413 - 请求实体太大,限制为 5000 字节
                 *     500 - 内部服务器错误
                 *     503 - 服务不可用
                 */
                HttpStatusCode statusCode = response.StatusCode;
                result = new HttpResponseMessage
                {
                    Content = new StringContent(statusCode.ToString(), Encoding.UTF8, "text/html")
                };
            }
            catch (Exception ex)
            {
                result = new HttpResponseMessage
                {
                    Content = new StringContent(ex.ToString(), Encoding.UTF8, "text/html"),
                    StatusCode = HttpStatusCode.InternalServerError
                };
            }

            return result;
        }
    }

    /*
     * 用于反序列化从 https://login.live.com/accesstoken.srf 获取到的结果
     */
    [DataContract]
    public class OAuthToken
    {
        [DataMember(Name = "access_token")]
        public string AccessToken { get; set; }
        [DataMember(Name = "token_type")]
        public string TokenType { get; set; }
    }

    /*
     * 用于从 https://login.live.com/accesstoken.srf 做 OAuth 验证的帮助类
     */
    public class OAuthHelper
    {
        /// <summary>
        /// 获取 https://login.live.com/accesstoken.srf 的 OAuth 验证的 access-token
        /// </summary>
        /// <param name="secret">在商店后台的 dashboard 中的“Application Secrets”中可以找到此值(可以在 https://apps.dev.microsoft.com/ 中查找)</param>
        /// <param name="sid">在商店后台的 dashboard 中的“Package SID”中可以找到此值(可以在 https://apps.dev.microsoft.com/ 中查找)</param>
        /// <returns></returns>
        public OAuthToken GetAccessToken(string secret, string sid)
        {
            var urlEncodedSecret = UrlEncode(secret);
            var urlEncodedSid = UrlEncode(sid);
            var body = String.Format("grant_type=client_credentials&client_id={0}&client_secret={1}&scope=notify.windows.com",
                                     urlEncodedSid,
                                     urlEncodedSecret);

            string response;
            using (WebClient client = new WebClient())
            {
                client.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
                response = client.UploadString("https://login.live.com/accesstoken.srf", body);
            }
            return GetOAuthTokenFromJson(response);
        }

        private OAuthToken GetOAuthTokenFromJson(string jsonString)
        {
            using (var ms = new MemoryStream(Encoding.Unicode.GetBytes(jsonString)))
            {
                var ser = new DataContractJsonSerializer(typeof(OAuthToken));
                var oAuthToken = (OAuthToken)ser.ReadObject(ms);
                return oAuthToken;
            }
        }

        private static string UrlEncode(string str)
        {
            StringBuilder sb = new StringBuilder();
            byte[] byStr = System.Text.Encoding.UTF8.GetBytes(str);
            for (int i = 0; i < byStr.Length; i++)
            {
                sb.Append(@"%" + Convert.ToString(byStr[i], 16));
            }

            return (sb.ToString());
        }
    }
}

BackgroundTask/PushNotification.xaml

<Page
    x:Class="Windows10.BackgroundTask.PushNotification"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:Windows10.BackgroundTask"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Grid Background="Transparent">
        <StackPanel Margin="10 0 10 10">

            <TextBlock Name="lblMsg" Margin="5" />

            <Button Name="btnCreateChannel" Content="create the channel" Margin="5" Click="btnCreateChannel_Click" />

            <TextBox Name="txtUri" Margin="5" />

            <TextBlock Margin="5">
                <Run>1、应用为推送通知通道向通知客户端平台发送请求。</Run>
                <LineBreak />
                <Run>2、通知客户端平台要求 WNS 创建通知通道。此通道以统一资源标识符 (URI) 的形式返回到调用设备。</Run>
                <LineBreak />
                <Run>3、通知通道 URI 由 Windows 返回到应用。</Run>
                <LineBreak />
                <Run>4、你的应用将 URI 发送到你自己的云服务。此回调机制是你自己的应用和你自己的服务之间的接口。使用安全的 Web 标准实现此回调是你的责任。</Run>
                <LineBreak />
                <Run>5、当你的云服务有要发送的更新时,它使用通道 URI 通知 WNS。通过安全套接字层 (SSL) 发送 TTP POST 请求(包括通知负载)来执行此操作。此步骤需要身份验证。</Run>
                <LineBreak />
                <Run>6、WNS 接收请求,并将通知路由到相应的设备。</Run>
            </TextBlock>
            <Image Source="wns.png" Margin="5" HorizontalAlignment="Left" Width="800" />

        </StackPanel>
    </Grid>

</Page>

BackgroundTask/PushNotification.xaml.cs

/*
 * 演示如何接收推送通知
 * 由于本例没有上商店,所以本例是无法演示的,需要看演示效果的话运行一下自己写的“打字通”的 /TypingGame/PushNotification/Sample.xaml,然后用其生成的 channel 地址在 /WebApi/Controllers/PushNotificationController.cs 推送通知
 *
 *
 * 注:
 * 1、在商店后台的 dashboard 中找到你的 app 的“包名”和“发布者”并替换你的 Package.appxmanifest 中的相关节点,类似如下
 *    <Identity Name="10437webabcd.**********E91" Publisher="CN=27514DEC-****-****-****-F956384483D0" Version="1.0.0.0" />
 *    也可以直接访问 https://apps.dev.microsoft.com/ 来查找这些信息
 *    最简单也是推荐的做法是:“选中项目”->“右键”->“应用商店”->“将应用程序与应用商店关联”,按提示操作后会自动将商店信息同步到你的项目中
 * 2、需要在 Package.appxmanifest 中增加后台任务声明,并勾选“推送通知”(经测试发现不做这一步也可以,但是为了保险还是加上吧)
 * 3、每次新建的 channel 有效期为 30 天
 *
 *
 * 另:
 * WNS - Windows Push Notification Service
 * 推送通知的服务端参见:/WebApi/Controllers/PushNotificationController.cs
 */

using System;
using Windows.Networking.PushNotifications;
using Windows.UI.Notifications;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

namespace Windows10.BackgroundTask
{
    public sealed partial class PushNotification : Page
    {
        public PushNotification()
        {
            this.InitializeComponent();
        }

        private async void btnCreateChannel_Click(object sender, RoutedEventArgs e)
        {
            // 创建一个推送通知信道,每个新建的 channel 有效期为 30 天,所以建议每次进入 app 后都重新建一个 channel(如果两次创建的间隔时间较短的话,则会复用之前的 channel 地址)
            PushNotificationChannel channel = await PushNotificationChannelManager.CreatePushNotificationChannelForApplicationAsync();
            // 接收到通知后所触发的事件
            channel.PushNotificationReceived += channel_PushNotificationReceived;

            // channel.Close(); // 关闭 channel
            // channel.ExpirationTime; // channel 的过期时间,此时间过后 channel 则失效

            // channel 的 uri 地址,服务端通过此 uri 向此 app 推送通知
            txtUri.Text = channel.Uri.ToString();
        }

        void channel_PushNotificationReceived(PushNotificationChannel sender, PushNotificationReceivedEventArgs args)
        {
            switch (args.NotificationType)
            {
                case PushNotificationType.Badge: // badge 通知
                    BadgeUpdateManager.CreateBadgeUpdaterForApplication().Update(args.BadgeNotification);
                    break;
                case PushNotificationType.Raw: // raw 通知
                    // 当收到推送的 raw 通知时,如果 app 在锁屏,则可以触发后台任务以执行相关的逻辑(PushNotificationTrigger)
                    string msg = args.RawNotification.Content;
                    break;
                case PushNotificationType.Tile: // tile 通知
                    TileUpdateManager.CreateTileUpdaterForApplication().Update(args.TileNotification);
                    break;
                case PushNotificationType.Toast: // toast 通知
                    ToastNotificationManager.CreateToastNotifier().Show(args.ToastNotification);
                    break;
                default:
                    break;
            }

            args.Cancel = true;
        }
    }
}

OK
[源码下载]

原文地址:https://www.cnblogs.com/webabcd/p/9211779.html

时间: 2024-11-03 02:12:02

背水一战 Windows 10 (121) - 后台任务: 推送通知的相关文章

背水一战 Windows 10 (118) - 后台任务: 后台下载任务(任务分组,并行或串行执行,组完成后通知)

[源码下载] 作者:webabcd 介绍背水一战 Windows 10 之 后台任务 后台下载任务(任务分组,并行或串行执行,组完成后通知) 示例演示后台下载任务的分组,以及如何设置组内任务是并行执行还是串行执行,以及组任务全部完成后如何 toast 或 tile 通知)BackgroundTask/TransferModel.cs /* * 扩展了 DownloadOperation 和 UploadOperation,用于 MVVM 绑定数据 */ using System; using S

背水一战 Windows 10 (119) - 后台任务: 后台下载任务(任务分组,组完成后触发后台任务)

[源码下载] 作者:webabcd 介绍背水一战 Windows 10 之 后台任务 后台下载任务(任务分组,组完成后触发后台任务) 示例演示后台下载任务的分组,以及组任务全部完成后如何触发后台任务/BackgroundTaskLib/BackgroundTaskTransfer.cs /* * 后台任务,用于演示指定的一组后台下载任务全部完成后如何触发此后台任务 * * BackgroundTransferCompletionGroup - 分组对象(用于实现“组任务全部完成后触发后台任务”)

背水一战 Windows 10 (120) - 后台任务: 后台上传任务

[源码下载] 作者:webabcd 介绍背水一战 Windows 10 之 后台任务 后台上传任务 示例演示 uwp 的后台上传任务BackgroundTask/TransferModel.cs /* * 扩展了 DownloadOperation 和 UploadOperation,用于 MVVM 绑定数据 */ using System; using System.ComponentModel; using Windows.Networking.BackgroundTransfer; nam

iOS 10 添加本地推送(Local Notification)

前言 iOS 10 中废弃了 UILocalNotification ( UIKit Framework ) 这个类,采用了全新的 UserNotifications Framework 来推送通知,从此推送通知也有了自己的标签 UN (这待遇真是没别人了),以及对推送功能的一系列增强改进(两个 extension 和 界面的体验优化),简直是苹果的亲儿子,因此推送这部分功能也成为开发中的重点. 本文主要查看了 iOS 10 的相关文档,整理出了在 iOS 10 下的本地推送通知,由于都是代码,

背水一战 Windows 10 (111) - 通知(Tile): secondary tile 模板之图片, secondary tile 模板之分组

[源码下载] 作者:webabcd 介绍背水一战 Windows 10 之 通知(Tile) secondary tile 模板之图片 secondary tile 模板之分组 示例1.本例用于演示 tile 显示模板的图片相关的知识点Notification/Tile/TemplateImage.xaml <Page x:Class="Windows10.Notification.Tile.TemplateImage" xmlns="http://schemas.mi

背水一战 Windows 10 (109) - 通知(Tile): 按计划显示 tile 通知, 轮询服务端以更新 tile 通知

[源码下载] 作者:webabcd 介绍背水一战 Windows 10 之 通知(Tile) 按计划显示 tile 通知 轮询服务端以更新 tile 通知 示例1.演示如何按计划显示 tile 通知(在指定的时间显示指定的 tile 通知,此特性在 application tile 和 secondary tile 中均支持)Notification/Tile/Schedule.xaml <Page x:Class="Windows10.Notification.Tile.Schedule

背水一战 Windows 10 (29) - 控件(文本类): RichTextBlock, RichTextBlockOverflow, RichEditBox

原文:背水一战 Windows 10 (29) - 控件(文本类): RichTextBlock, RichTextBlockOverflow, RichEditBox [源码下载] 作者:webabcd 介绍背水一战 Windows 10 之 控件(文本类) RichTextBlock RichTextBlockOverflow RichEditBox 示例1.RichTextBlock 的示例Controls/TextControl/RichTextBlockDemo.xaml <Page

【WP 8.1开发】手机客户端应用接收推送通知

上一篇文章中,已经完成了用于发送通知的服务器端,接下来我们就用这个服务端来测试一下. 在开始测试之前,我们要做一个接收通知的WP应用. 1.启动VS Express for Windows,新建项目,在项目模板中选择“空白应用程序(Windows Phone)”. 2.既然要接收通知,肯定少不了Toast.磁贴这几样常用的通知的,故我们得先准备一些图片. 在“解决方案资源管理器”中,双击打开清单文件,切换到“可见资产”选项卡,这个“资产”指的不你的银行卡存款有多少,而是你的应用中的一些如图片.音

Windows phone Toast消息推送 学习笔记

简单介绍: Windows phone平台支持三种形式的推送通知: 1.Tile——也就是在Start屏幕程序平铺图标 2.Toast——创建一个显示在当前屏幕中的Toast弹出窗口 3.Raw——有应用程序自己来处理的通知:对于用户是透明的. 这三种推送的过程是相同的,都涉及到三方:Windows phone应用程序.基于云的通知服务(Notification Service,由微软提供).通知源. 推送通知的过程如下图所示: 顺序如下:1.具有消息推送功能的应用发出消息推送 2.向微软推送通