重新想象 Windows 8 Store Apps (67) - 后台任务: 推送通知

简介: 原文:重新想象 Windows 8 Store Apps (67) - 后台任务: 推送通知[源码下载] 重新想象 Windows 8 Store Apps (67) - 后台任务: 推送通知 作者:webabcd介绍重新想象 Windows 8 Store Apps 之 后台任务 推送通...
原文: 重新想象 Windows 8 Store Apps (67) - 后台任务: 推送通知

[源码下载]


重新想象 Windows 8 Store Apps (67) - 后台任务: 推送通知



作者:webabcd


介绍
重新想象 Windows 8 Store Apps 之 后台任务

  • 推送通知



示例
1、客户端
BackgroundTask/PushNotification.xaml

<Page
    x:Class="XamlDemo.BackgroundTask.PushNotification"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:XamlDemo.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="120 0 0 0">
            
            <TextBlock Name="lblMsg" FontSize="14.667" TextWrapping="Wrap" />
            
            <Button Name="btnCreateChannel" Content="create the channel" Margin="0 10 0 0" Click="btnCreateChannel_Click" />
            
            <TextBox Name="txtUri" Margin="0 10 10 0" />
            
            <Image Source="wns.png" Margin="0 10 0 0" HorizontalAlignment="Left" Width="800" />
            
        </StackPanel>
    </Grid>
</Page>

BackgroundTask/PushNotification.xaml.cs

/*
 * 演示如何接收推送通知
 * 
 * 注:
 * 需要在 Package.appxmanifest 中增加后台任务声明,并勾选“推送通知”
 * 在 win8 商店创建了应用后,需要将此 app 的商店中的 identity 复制到 Package.appxmanifest 的 identity 节点
 * 不能在模拟器中运行
 * 每次新建的 channel 有效期为 30 天
 * 
 * 另:
 * WNS - Windows Push Notification Service
 * 推送通知的服务端参见:WebServer/PushNotification 内的文件
 */

using System;
using Windows.ApplicationModel.Background;
using Windows.Networking.PushNotifications;
using Windows.UI.Notifications;
using Windows.UI.Popups;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

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

        private async void btnCreateChannel_Click(object sender, RoutedEventArgs e)
        {
            // 当收到推送的 raw 通知时,如果 app 在锁屏,则可以触发后台任务以执行相关的逻辑(PushNotificationTrigger)
            BackgroundAccessStatus status = BackgroundExecutionManager.GetAccessStatus();
            if (status == BackgroundAccessStatus.Unspecified)
            {
                status = await BackgroundExecutionManager.RequestAccessAsync();
            }
            if (status == BackgroundAccessStatus.Denied)
            {
                await new MessageDialog("请先将此 app 添加到锁屏").ShowAsync();
                return;
            }

            // 创建一个推送通知信道,每个新建的 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;            
        }
    }
}

Package.appxmanifest

<?xml version="1.0" encoding="utf-8"?>
<Package xmlns="http://schemas.microsoft.com/appx/2010/manifest">
  <!--以下借用“贪吃的蛇”的 Identity,以便演示推送通知-->
  <!--Identity Name="10437webabcd.173815756DD78" Publisher="CN=27514DEC-C708-4EDB-BFEA-F956384483D0" Version="1.0.0.0" /-->
  <Identity Name="webabcd.win8.XamlDemo" Publisher="CN=wanglei" Version="1.0.0.0" />
</Package>


2、服务端
WebServer/PushNotification/OAuthToken.cs

/*
 * 用于反序列化从 https://login.live.com/accesstoken.srf 获取到的结果
 */

using System.Runtime.Serialization;

namespace WebServer.PushNotification
{
    [DataContract]
    public class OAuthToken
    {
        [DataMember(Name = "access_token")]
        public string AccessToken { get; set; }
        [DataMember(Name = "token_type")]
        public string TokenType { get; set; }
    }
}

WebServer/PushNotification/OAuthHelper.cs

/*
 * https://login.live.com/accesstoken.srf 的 OAuth 验证的帮助类
 */

using System;
using System.IO;
using System.Net;
using System.Runtime.Serialization.Json;
using System.Text;

namespace WebServer.PushNotification
{
    public class OAuthHelper
    {
        /// <summary>
        /// 获取 https://login.live.com/accesstoken.srf 的 OAuth 验证的 access-token
        /// </summary>
        /// <param name="secret">在 win8 商店创建 app 后获取到的 “客户端密钥”</param>
        /// <param name="sid">在 win8 商店创建 app 后获取到的 “程序包安全标识符(SID)”</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());
        }
    }
}

WebServer/PushNotification/Push.aspx.cs

/*
 * 演示如何向 app 推送通知
 * 
 * 注:
 * 关于推送通知服务请求和响应头的详细说明参见:http://msdn.microsoft.com/zh-cn/library/windows/apps/hh465435.aspx
 */

using System;
using System.IO;
using System.Net;
using System.Text;

namespace WebServer.PushNotification
{
    public partial class Push : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            // 向某个 app 推送通知的 channel 地址
            string notifyUrl = "https://sin.notify.windows.com/?token=AgYAAABQnraWSMQXRveiofxSXGKMHaPB84FLMhFa3D6TQZRHzRSPeByl%2f1O%2frPAcc3ipjpT2cQXfivh589zEV8AOYkR%2fLwXoT2esZnC3hS%2fN7q94ZzJFLnpQsDsYNolFiEAhbHQ%3d";

            // 在 win8 商店创建 app 后获取到的 “程序包安全标识符(SID)”
            string sid = "ms-app://s-1-15-2-1530173461-470787880-3155417234-2904423500-2475821181-4070965884-3773336209";
            // 在 win8 商店创建 app 后获取到的 “客户端密钥”
            string secret = "bs08Acs1RG7jB7pkGVMh8EmGKCG3pH+3";

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

            try
            {
                HttpWebRequest myRequest = (HttpWebRequest)WebRequest.Create(notifyUrl);

                // toast, tile, badge 为 text/xml; raw 为 application/octet-stream
                myRequest.ContentType = "text/xml";
                // 推送消息的类型:wns/toast | wns/badge | wns/tile | wns/raw
                myRequest.Headers.Add("X-WNS-Type", "wns/toast");
                // 设置 access-token
                myRequest.Headers.Add("Authorization", String.Format("Bearer {0}", token.AccessToken));

                // 注:app 通过 toast 激活后可以通过 OnLaunched() 中的 args.Arguments 来获取此处 launch 指定的值
                string toastMessage = "<toast launch='param'><visual version='1'><binding template='ToastText01'><text id='1'>推送通知:" + DateTime.Now.ToString("mm:ss") + "</text></binding></visual></toast>";
                byte[] buffer = Encoding.UTF8.GetBytes(toastMessage);

                myRequest.ContentLength = buffer.Length;
                myRequest.Method = "POST";

                using (Stream stream = myRequest.GetRequestStream())
                {
                    stream.Write(buffer, 0, buffer.Length);
                }

                using (HttpWebResponse webResponse = (HttpWebResponse)myRequest.GetResponse())
                {
                    /*
                     * 响应代码说明
                     *     200 - OK,WNS 已接收到通知
                     *     400 - 错误的请求
                     *     401 - 未授权,token 可能无效
                     *     403 - 已禁止,manifest 中的 identity 可能不对
                     *     404 - 未找到
                     *     405 - 方法不允许
                     *     406 - 无法接受
                     *     410 - 不存在,信道不存在或过期
                     *     413 - 请求实体太大,限制为 5000 字节
                     *     500 - 内部服务器错误
                     *     503 - 服务不可用
                     */
                    Response.Write(webResponse.StatusCode.ToString()); //如果成功应该是返回 200 ok
                }
            }
            catch (Exception ex)
            {
                Response.Write(ex.ToString());
            }
        }
    }
}



OK
[源码下载]

目录
相关文章
|
24天前
|
C# Windows
【Azure App Service】在App Service for Windows上验证能占用的内存最大值
根据以上测验,当使用App Service内存没有达到预期的值,且应用异常日志出现OutOfMemory时,就需要检查Platform的设置是否位64bit。
41 11
|
4月前
|
Java 应用服务中间件 开发工具
[App Service for Windows]通过 KUDU 查看 Tomcat 配置信息
[App Service for Windows]通过 KUDU 查看 Tomcat 配置信息
|
4月前
|
Java 应用服务中间件 Windows
【App Service for Windows】为 App Service 配置自定义 Tomcat 环境
【App Service for Windows】为 App Service 配置自定义 Tomcat 环境
|
4月前
|
PHP Windows
【Azure App Service for Windows】 PHP应用出现500 : The page cannot be displayed because an internal server error has occurred. 错误
【Azure App Service for Windows】 PHP应用出现500 : The page cannot be displayed because an internal server error has occurred. 错误
|
4月前
|
网络安全 API 数据安全/隐私保护
【Azure App Service】.NET代码实验App Service应用中获取TLS/SSL 证书 (App Service Windows)
【Azure App Service】.NET代码实验App Service应用中获取TLS/SSL 证书 (App Service Windows)
|
4月前
|
Shell PHP Windows
【Azure App Service】Web Job 报错 UNC paths are not supported. Defaulting to Windows directory.
【Azure App Service】Web Job 报错 UNC paths are not supported. Defaulting to Windows directory.
|
4月前
|
存储 Linux Windows
【应用服务 App Service】App Service For Windows 如何挂载Storage Account File Share 示例
【应用服务 App Service】App Service For Windows 如何挂载Storage Account File Share 示例
|
15天前
|
网络安全 Windows
Windows server 2012R2系统安装远程桌面服务后无法多用户同时登录是什么原因?
【11月更文挑战第15天】本文介绍了在Windows Server 2012 R2中遇到的多用户无法同时登录远程桌面的问题及其解决方法,包括许可模式限制、组策略配置问题、远程桌面服务配置错误以及网络和防火墙问题四个方面的原因分析及对应的解决方案。
|
20天前
|
监控 安全 网络安全
Windows Server管理:配置与管理技巧
Windows Server管理:配置与管理技巧
59 3
|
24天前
|
存储 安全 网络安全
Windows Server 本地安全策略
由于广泛使用及历史上存在的漏洞,Windows服务器成为黑客和恶意行为者的主要攻击目标。这些系统通常存储敏感数据并支持关键服务,因此组织需优先缓解风险,保障业务的完整性和连续性。常见的威胁包括勒索软件、拒绝服务攻击、内部威胁、恶意软件感染等。本地安全策略是Windows操作系统中用于管理计算机本地安全性设置的工具,主要包括用户账户策略、安全选项、安全设置等。实施强大的安全措施,如定期补丁更新、网络分段、入侵检测系统、数据加密等,对于加固Windows服务器至关重要。