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

  • 相关阅读:
    TAOCP读书笔记——Search(1)
    JAVA进程间通信
    C++ Primer 阅读总结 (1)
    初来乍到
    [C#]手把手教你打造Socket的TCP通讯连接(二)
    [C#]手把手教你打造Socket的TCP通讯连接(三)
    数字ToString作为货币显示并且带小数
    [C#]手把手教你打造Socket的TCP通讯连接(一)
    [C#]手把手教你打造Socket的TCP通讯连接(四)
    WPF中使用ItemTemplate把所有Item都控制为指定大小
  • 原文地址:https://www.cnblogs.com/webabcd/p/3385338.html
Copyright © 2020-2023  润新知