当前位置: 首页 > news >正文

【WP 8.1开发】自定义(RAW)通知的使用

继续前面的话题,还是推送通知。上一篇文章中遗留了RAW通知的推送没有给各位演示,特特地留到现在,不为别的,只为这个RAW通知有点意思,玩起来会比较有意思。官方文档将RAW通知译为“原始通知”,这里还是沿用官方的翻译。

在开始吹牛之前,先说一说与推送通知相关的要点。

有人说,如果我有22222222个客户端,岂不是都要获取每个手机客户端的通道URL来推送吗?是的。于是有人想到了所谓的“极光推送”,忽悠人的,“极光”显然偷换了概念。我们得明确,在什么情况下才会考虑使用推送。

推送好比服务器与手机客户端的“私人对话”,即当我们要为每一位客户发送个性化的消息时,才叫推送,说白了,就是每个用户收到的消息不相同,比如QQ就是这情况,每人的聊天记录都不相同。要是你打算向所有客户发送相同的信息,就不应该使用推送,使用更简单处理的Socket通信、或干脆用Web/WCF服务,把消息放到服务上,每个客户端自动去读取。你可以结合后台任务,特别计划后台,可以控制信息更新的频率(比如每天获取一次),获取到更新信息再通过Toast或磁贴来提醒一下用户就好了。

==============================================================

好了,废话结束,下面是正文。

RAW通知比较灵活,它不像Toast、磁贴、锁屏通知那样需要严格遵守固定的XML格式,RAW通知的内容或结构都可以自己来定义,然后把通知内容POST到推送通道URL即可,在发送时建议使用UTF-8编码,这样遇到中文字符也不至于在客户端收到乱码,别然并不绝对地说一定会变成乱码,但是谨慎一点肯定不是坏事。

 

在手机客户端,一般我们会结合后台任务来接收RAW通知,这样做的好处在于:

1、后台任务可以独立、有计划、有条件地运行,既不受前台UI影响,也不至于影响系统性能。大家都知道,WP手机是必须保持它刷刷刷地流畅的,不能因为我们开发的应用让系统不再刷刷刷,这样很不好。

2、有了后台接收,就算应用不在运行,都可以保证收到通知,前提是要有网络可用。

 

好,我想一想,给大家做个什么演示好呢?这样吧,为了使示例更容易理解,假设我的服务器端是一个电子商务平台,专门销售山寨七匹林男装的,每当有新的山寨品上架,服务会自动通知指定客户优惠打折的通知,我们就用RAW通知来实现。

1、启动VS,新建一个WP 8.1 应用程序。

2、在解决方案中添加一个“Windows 运行时组件”的项目,如下图。

注意,是Windows运行时组件,不是类库,不要创建类库项目。

项目名字你自己取,比如叫“后台怪兽”也行。这个windows 运行时组件项目用来定义咱们的后台任务。

 

3、声明一个类,并且这个类必须实现Windows.ApplicationModel.Background.IBackgroundTask接口,这个接口包含一个Run方法,我们要实现这个方法。

    public sealed class NotifiBackTask:Windows.ApplicationModel.Background.IBackgroundTask
    {
        public void Run(Windows.ApplicationModel.Background.IBackgroundTaskInstance taskInstance)
        {
            // 在这里编写后台处理代码

        }
    }

下面是后台的实现代码。

 

        public void Run(Windows.ApplicationModel.Background.IBackgroundTaskInstance taskInstance)
        {
            // 在这里编写后台处理代码
            Windows.Networking.PushNotifications.RawNotification notification = taskInstance.TriggerDetails as Windows.Networking.PushNotifications.RawNotification;

            if (notification != null)
            {
                // 获取RAW通知的内容
                string message = notification.Content;
                // 由于内容是以|作为分隔符的,所以我们要取得标题和内容
                string[] items = message.Split('|');
                // 保存数据
                Windows.Storage.ApplicationData.Current.LocalSettings.Values["title"] = items[0];
                Windows.Storage.ApplicationData.Current.LocalSettings.Values["content"] = items[1];
                // 更新磁贴
                Windows.Data.Xml.Dom.XmlDocument doc = Windows.UI.Notifications.TileUpdateManager.GetTemplateContent(Windows.UI.Notifications.TileTemplateType.TileSquare150x150Text02);
                var nodes = doc.SelectNodes("tile/visual/binding/text");
                if (nodes.Count >= 2)
                {
                    // 修改XML值
                    ((XmlElement)nodes[0]).InnerText = items[0];
                    ((XmlElement)nodes[1]).InnerText = items[1];
                }
                // 更新磁贴
                TileUpdateManager.CreateTileUpdaterForApplication().Update(new TileNotification(doc));

                // 顺便也发一下Toast通知
                XmlDocument doctoast = ToastNotificationManager.GetTemplateContent(ToastTemplateType.ToastText02);
                var txtnodes = doctoast.GetElementsByTagName("text");
                if (txtnodes.Count > 1)
                {
                    // 修改XML值
                    ((XmlElement)txtnodes[0]).InnerText = items[0];
                    ((XmlElement)txtnodes[1]).InnerText = items[1];
                }
                // 发送Toast通知
                ToastNotificationManager.CreateToastNotifier().Show(new ToastNotification(doctoast));
            }
      
}


当Run方法被调用时,会把一个实现了IBackgroundTaskInstance接口的对象实例通过参数传递进来,它表示当前正在执行的后台任务的实例。接着通过访问taskInstance.TriggerDetails属性获得一个跟触发当前后台任务相关联的对象。

我们这个后台任务是由于RAW通知到达而触发的,因此,TriggerDetails属性所引用的对象就是一个RawNotification实例,再经过Content属性就能得到RAW通知的内容了。

我测试的时候,是用一个“|”符号把标题和正文分符开来,因此应用程序在收到通知后要对内容字符进行分割处理,以得到标题和正文。

最后,把收到的内容保存到本地存储中,并向用户发送Toast提醒,同时更新磁贴。

 

4、回到WP应用项目,添加对刚才的后台任务的引用。

5、打开清单文件,切换到“声明”选项卡,添加一个后台任务,触发器为“推送通知”,入口点为刚才定义的后台类的类名,包含命名空间名字。如下图。

 

6、修改清单文件仅仅是允许某个后台任务,要让后台任务真正运行起来,还需要在代码中进行注册。

            string taskName = "back_notifi"; //后台任务名称
            string entryPoint = "RawNotificationBackgroundTask.NotifiBackTask"; //入口点
            // 检查是否许后台任务
            var result = await BackgroundExecutionManager.RequestAccessAsync();
            if (result == BackgroundAccessStatus.AllowedMayUseActiveRealTimeConnectivity)
            {
                // 检查是否已经注册后台任务
                var task = BackgroundTaskRegistration.AllTasks.Values.FirstOrDefault((t) => t.Name == taskName);
                // 如果未注册,则进行注册
                if (task == null)
                {
                    BackgroundTaskBuilder tb = new BackgroundTaskBuilder();
                    tb.TaskEntryPoint = entryPoint;
                    tb.Name = taskName;
                    // 触发器为推送通知触发器
                    tb.SetTrigger(new PushNotificationTrigger());
                    // 运行条件为网络可用
                    tb.AddCondition(new SystemCondition(SystemConditionType.InternetAvailable));
                    // 注册
                    tb.Register();
                }
            }

var task = BackgroundTaskRegistration.AllTasks.Values.FirstOrDefault((t) => t.Name == taskName);一行代码是检查一下后台任务是否已经注册,如果已经注册了,就不要再注册了,后台任务的名字必须是唯一的,不能与其他后台任务重复。

 

记得:要将清单中的标识与应用商店中的信息同步,请参考上一篇文章。

 

7、现在,以管理员的身份运行我们前面开发的测试服务端,通知类型选择“自定义”。

 

 

发送通知后,在手机上就会收到相应的通知,请看下面的美图。

 

 

 

示例代码下载:http://files.cnblogs.com/tcjiaan/RawNotificationWPClientApp.rar

 

相关文章:

  • java 递归函数
  • jQuery Validation Engine 表单验证
  • GLES Shader Language 易错集锦
  • python的getopt
  • mac下mysql忘记root密码
  • 编程语言,变量
  • 关于git和github用法
  • Python学习(一)——数据类型
  • 定制微型Linux系统(续)
  • Redis进阶 ----事务
  • 【Spark亚太研究院-构建Spark集群-配置Hadoop伪分布模式并运行Wordcount(2)
  • 《设计模式系列》---组合模式
  • Exchange 2013sp1邮件系统部署-(九)
  • 点与不规则图形关系判断
  • Android开发之初识Camera图像采集
  • [iOS]Core Data浅析一 -- 启用Core Data
  • 〔开发系列〕一次关于小程序开发的深度总结
  • 002-读书笔记-JavaScript高级程序设计 在HTML中使用JavaScript
  • android百种动画侧滑库、步骤视图、TextView效果、社交、搜房、K线图等源码
  • Date型的使用
  • es6要点
  • Fastjson的基本使用方法大全
  • quasar-framework cnodejs社区
  • rc-form之最单纯情况
  • Vue ES6 Jade Scss Webpack Gulp
  • 对象管理器(defineProperty)学习笔记
  • 函数式编程与面向对象编程[4]:Scala的类型关联Type Alias
  • 基于组件的设计工作流与界面抽象
  • 记录一下第一次使用npm
  • 前端路由实现-history
  • 悄悄地说一个bug
  • 线性表及其算法(java实现)
  • 学习ES6 变量的解构赋值
  • 译米田引理
  • 原生js练习题---第五课
  • 正则与JS中的正则
  • zabbix3.2监控linux磁盘IO
  • ​比特币大跌的 2 个原因
  • #define 用法
  • $refs 、$nextTic、动态组件、name的使用
  • (17)Hive ——MR任务的map与reduce个数由什么决定?
  • (70min)字节暑假实习二面(已挂)
  • (C语言)深入理解指针2之野指针与传值与传址与assert断言
  • (Redis使用系列) SpringBoot 中对应2.0.x版本的Redis配置 一
  • (二) Windows 下 Sublime Text 3 安装离线插件 Anaconda
  • (简单有案例)前端实现主题切换、动态换肤的两种简单方式
  • (三)elasticsearch 源码之启动流程分析
  • (译)计算距离、方位和更多经纬度之间的点
  • (转)c++ std::pair 与 std::make
  • (转)socket Aio demo
  • ./和../以及/和~之间的区别
  • .axf 转化 .bin文件 的方法
  • .equal()和==的区别 怎样判断字符串为空问题: Illegal invoke-super to void nio.file.AccessDeniedException
  • .jks文件(JAVA KeyStore)
  • .net core 微服务_.NET Core 3.0中用 Code-First 方式创建 gRPC 服务与客户端