重新想象 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
[源码下载]

目录
相关文章
|
Linux C++ Windows
【Azure 应用服务】Azure App Service(Windows)环境中如何让.NET应用调用SAP NetWeaver RFC函数
【Azure 应用服务】Azure App Service(Windows)环境中如何让.NET应用调用SAP NetWeaver RFC函数
138 0
【Azure 应用服务】Azure App Service(Windows)环境中如何让.NET应用调用SAP NetWeaver RFC函数
|
10月前
|
C# Windows
【Azure App Service】在App Service for Windows上验证能占用的内存最大值
根据以上测验,当使用App Service内存没有达到预期的值,且应用异常日志出现OutOfMemory时,就需要检查Platform的设置是否位64bit。
160 11
|
Java 应用服务中间件 开发工具
[App Service for Windows]通过 KUDU 查看 Tomcat 配置信息
[App Service for Windows]通过 KUDU 查看 Tomcat 配置信息
133 2
|
Java 应用服务中间件 Windows
【App Service for Windows】为 App Service 配置自定义 Tomcat 环境
【App Service for Windows】为 App Service 配置自定义 Tomcat 环境
114 2
|
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. 错误
209 1
|
PHP 开发工具 git
【Azure 应用服务】在 App Service for Windows 中自定义 PHP 版本的方法
【Azure 应用服务】在 App Service for Windows 中自定义 PHP 版本的方法
118 1
|
网络安全 API 数据安全/隐私保护
【Azure App Service】.NET代码实验App Service应用中获取TLS/SSL 证书 (App Service Windows)
【Azure App Service】.NET代码实验App Service应用中获取TLS/SSL 证书 (App Service Windows)
114 0
|
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.
109 0
|
存储 Linux Windows
【应用服务 App Service】App Service For Windows 如何挂载Storage Account File Share 示例
【应用服务 App Service】App Service For Windows 如何挂载Storage Account File Share 示例
113 0
|
应用服务中间件 nginx Windows
【Azure 应用服务】在App Service for Windows中实现反向代理
【Azure 应用服务】在App Service for Windows中实现反向代理
131 0