【Win 10 应用开发】Toast通知激活应用——前台&后台

原文:【Win 10 应用开发】Toast通知激活应用——前台&后台

老周最近热衷于讲故事,接下来还是讲故事时间。

有人问我:你上大学的时候,有加入过学生会吗?读大学有没有必要加入学生会?

哎哟,这怎么回答呢,从短期来说,加入学生会有点用,至少可以娱乐一下,运气好的话,说不定能遇到红颜知己,但这概率相当低。从长远发展看嘛,是没什么用。老周当年读了四年本科,在学生会混了四年,什么名堂也没混出来。

一方面老周向来不求虚名,所以也没去参选所谓的什么部长、主席之类的,这些“官衔”听起来很高大上,实际上很庸俗蠢。既然没兴趣,因而老周更不需要去搞那些见不得人的勾当,什么勾当?你懂的。其次,老周没感觉到这些职务,对将来的职业生涯发展有什么帮助,基本上属于混日子罢了。

老周当初一上大学,本不想进什么学生会天地会之类的,之所以进了,纯属意外,简直太意外了,事情是这样的。话说那天学生会招新,尽管老周的母校比较老旧,但校园里还是被各处摆摊招新的学兄学姐们弄得像大观园似的,热闹非常。

谁不知道,大观园里美女多,于是我宿舍的室友开始动心了,有两个人鼓起勇气,决定明天去面试。本来跟我没什么关系,谁想第二天,又有一位室友感兴趣了,他们索性商量全宿舍一起出动。老周本不想去,就被他们硬拉着去。

一伙漫无目的地随处看,我以为他们是去看美女的,原来他们还真的去面试了,走着走着,我们进入了一个教室,里面坐着几位师兄和师姐。进去前要在门口登记,写上个人信息,然后排队面试(教室里都没几个人,排什么队),我说我不是来面试的,是陪室友来玩玩的。听我一说完,一位师兄叫我出去走廊外面等。

正当我往外走时,另一位师兄又把我叫回来,说既然来了就面面试吧,没事的。这时候我才知道,他们是要招书法高手的。老周虽不敢当什么高手,但从小就握过几年毛笔,不防耍耍。就这样,老周就莫名其妙地进了学生会。

想来有趣,本来想进的,没进;我本不想进的,反而进了。真是世事无常,祸福相依啊。

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

故事讲完了,下面说正经话。

话说上一回,老周给大伙伴们介绍了win 10中Toast通知的新型模板,既包含有旧版本的兼容格式,也有用于通用平台的“自适应”通知。前一文章中,老周主要介绍了XML文档的基本格式,并演示了两个例子。

今天,咱们探讨一下如何在Toast通知中使用交互命令,并通过交互命令激活应用程序。所谓交互命令,就是在Toast通知的界面上添加一些可以让用户操作的元素,来与应用程序进行互动。这些交互元素主要有:

1、按钮。用action元素来指定,用户点击按钮后会激活应用程序,并把用户所点击的按钮的参数作为激活参数传递给应用程序。

2、输入框。就是一个文本框,用户可以在里面输入文本。

3、选择列表。类似于下拉列表框,用户可以在里面选择一个项。

这些交互元素都统一放到actions元素下面。

举个例子,比如这样:

<toast>
  <visual>
    <binding template="ToastGeneric">
      <text>唱山歌</text>
      <text>一起去唱山歌吧.</text>
      <image placement="appLogoOverride" src="c.png" />
    </binding>
  </visual>
  <actions>
    <action content="报名" arguments="join" imageUri="jn.png" />
    <action content="不去" arguments="cancel" />
  </actions>
</toast>

大家可以想象一下这个Toast通知是什么样子的,现在不截图给你看,待会儿咱们做示例时再看。

首先,visual元素在前一篇烂文中讲过,是描述toast通知的可视化部分,第一个text被视为标题,所以显示出来字体较大,第二个text作为正文,显示一行文本。image元素指定一个图像,因为设置了placement="appLogoOverride",表明这个图像会替换应用的默认图标,显示在通知的左上角。

接下来,重点关注actions元素,actions元素下面专门用来放置交互命令,有两个元素可用:

<action>:表示定义一个命令按钮。例如:

<action content = "确定"  arguments = "yes"  activationType ="foreground或background" imageUrl="b.png"  />

content表示要在按钮上显示的文本,上面例子在按钮上显示“确定”。imageUrl表示显示在按钮上的图标,如果不用图标,就可以不设置imageUrl属性。arguments用来指定一个参数,这个参数是你自己定的,比如我这里叫yes,当用户点击按钮后,arguments的值会传递给应用程序,这样应用程序才会知道你到底点击了哪个按钮。

activationType指示以何种方式激活应用程序,如果值为foreground,则表明toast通知将在前台激活应用程序,这时候用户可以看见应用程序;如果值为background,表明toast通知通过后台方式激活应用,此时用户看不到应用程序,后台激活必须指定一个后台任务,当激活时就会执行后台任务。如果值为protocol,表示将通过协议来激活应用程序。

如果希望用户可以在Toast通知上输入内容,可以这样定义XML:

<input id="name" type="text" />

Toast通知上会显示一个文本框,id属性是必须指定的,而且必须是actions中的唯一值,不能重复,这个id值在激活应用程序时会传递给应用。type属性指定input元素的类型,text表示文本框,让用户输入文本。如果是selection表示显示一个列表选择框,用户只能从中选择一个项。

如果type为selection,那么input元素下会包含N个selection元素,每个selection元素表示一个选项,如

<input id="age" type="selection">
    <selection content="五岁" id="5" />
    <selection content="七岁" id="7" />
</input>

上面例子,定义了两个选项,每个selection的id值必须唯一,它表示该项的值,这个id也会传递给被激活的程序。content表示项中显示的文本,用来给你看的。即当toast弹出时,在下拉列表中,你看到的是五岁、七岁两个选项。

下面我们来实战一下,先看Toast通知如何从前台激活应用。

首先构造XML文档。

            string visual = "<visual>" +
                                "<binding template=\"ToastGeneric\">" +
                                    "<text>宇宙第一应用</text>" +
                                    "<text>应用正在收集您的信息。</text>" +
                                "</binding>" +
                             "</visual>";
            string actions = "<actions>" +
                                "<input id=\"name\" type=\"text\" placeHolderContent=\"请输入姓名\" />" +
                                "<input id=\"city\" type=\"text\" placeHolderContent=\"请输入城市\" />" +
                                "<action content=\"确定\" arguments=\"ok\" />" +
                                "<action content=\"取消\" arguments=\"cancel\" activationType=\"foreground\" />" +
                             "</actions>";
            string toastXml = $"<toast>{visual}{actions}</toast>";

有一点大伙要注意,当input和action元素同时使用时,input元素必须放在action元素的前面。placeHolderContent属性主要设置占位文本,即当文本框中没有输入任何内容时显示的文本。

上面的Toast通知定义了两个可供输入的文本框,以及两个命令按钮。

下面代码显示通知。

            // 加载XML文档
            XmlDocument doc = new XmlDocument();
            doc.LoadXml(toastXml);
            // 显示通知
            ToastNotification notification = new ToastNotification(doc);
            ToastNotifier notifier = ToastNotificationManager.CreateToastNotifier();
            notifier.Show(notification);

正因为应用程序是被前台激活的,所以肯定要为Application类作激活处理,在App类中,重写基类的OnActivated方法。

        protected override void OnActivated(IActivatedEventArgs args)
        {
            // 判断激活类型
            // 确认是由Toast通知激活应用
            if (args.Kind == ActivationKind.ToastNotification)
            {
                // 转换参数类型
                ToastNotificationActivatedEventArgs toastargs = (ToastNotificationActivatedEventArgs)args;
                // 获取页面引用
                Frame root = Window.Current.Content as Frame;
                if (root == null)
                {
                    root = new Frame();
                    Window.Current.Content = root;
                }
                if (root.Content == null)
                {
                    root.Navigate(typeof(MainPage));
                }
                MainPage page = (MainPage)root.Content;
                // 判断用户点击哪个按钮
                string activeargs = toastargs.Argument;
                if (activeargs == "ok") //确定按钮
                {
                    // 获取用户输入的内容
                    string name = toastargs.UserInput["name"] as string;
                    string city = toastargs.UserInput["city"] as string;
                    page.ShowTextFromForeactivation($"用户点击了确定按钮,输入的内容为:\n姓名:{name}\n城市:{city}。");
                }
                else //取消按钮
                {
                    page.ShowTextFromForeactivation("用户点击了取消按钮。");
                }
            }
            Window.Current.Activate();
        }

先要通过方法参数的Kind属性来判断一下应用程序是不是被Toast通知所激活的,如果值是ToastNotification,证明应用程序是被Toast通知激活的。

然后要把方法参数的类型转化为ToastNotificationActivatedEventArgs类型,ToastNotificationActivatedEventArgs类专用于Toast通知的激活。

Argument属性中取得的值就是被点击的action的arguments属性中的值,上面我定义的toast有两个action,arguments的值分别为ok和cancel,如果用户点击了确定按钮,那么从ToastNotificationActivatedEventArgs对象的Argument属性得到的值为ok,否则就是cancel。

UserInput属性获取的就是input元素的值,属性类型为ValueSet,实际上是一个字典类型。Key为Toast通知中input元素的id,Value的值是input元素中输入的内容。通过UserInput属性,程序就知道用户在文本框中输入了什么内容。

运行应用程序,当通知弹出时,输入相关内容,如下图。

输入一些文本后,然后点击确定按钮,然后应用程序被激活,会看到主页面上显示从Toast通知传递到应用程序的输入数据。如下图所示。

---------------------------------------------------------------------------------------------------

上面演示的是Toast通知从前台激活应用程序,下面来看看后台激活。Toast通知从后台激活应用程序,用户不会看到应用程序界面,但应用程序会在后台任务中处理从Toast通知传递到应用程序的数据。

要实现从后台处理Toast通知,首先要实现一个后台任务。记住后台任务要在一个独立的Runtime组件项目中。后台的实现代码如下:

    public sealed class ToastBgTask : IBackgroundTask
    {
        public async void Run(IBackgroundTaskInstance taskInstance)
        {
            var deferral = taskInstance.GetDeferral();

            ToastNotificationActionTriggerDetail details = taskInstance.TriggerDetails as ToastNotificationActionTriggerDetail;
            if (details != null)
            {
                // 先确认用户点击了yes按钮
                string cmdargs = details.Argument;
                if (cmdargs == "yes")
                {
                    // 获取选择的项
                    object value = details.UserInput["ut"];
                    // 保存数据
                    StorageFolder local = ApplicationData.Current.LocalFolder;
                    JsonObject jsobj = new JsonObject();
                    jsobj.SetNamedValue("updatetime", JsonValue.CreateNumberValue(Convert.ToDouble(value)));
                    StorageFile newFile = await local.CreateFileAsync("data.json", CreationCollisionOption.ReplaceExisting);
                    await FileIO.WriteTextAsync(newFile, jsobj.Stringify(), Windows.Storage.Streams.UnicodeEncoding.Utf8);
                }
            }

            deferral.Complete();
        }
    }

当Toast通知激活后台任务后,可以从 taskInstance.TriggerDetails属性获取到一个ToastNotificationActionTriggerDetail对象实例。和前台激活一样,通过Argument属性可以获取Toast通知中被用户点击的action元素的参数。从UserInput属性可以获取到input元素的id值。

后台任务完成后,记得要在主项目中引用,这个老周已经重复了几千遍了。

然后打开清单文件,在Package/Applications/Application节点下添加后台任务声明。

    <Extensions>
      <Extension Category="windows.backgroundTasks" EntryPoint="BackgroundTasks.ToastBgTask">
        <BackgroundTasks>
          <Task Type="general"/>
        </BackgroundTasks>
      </Extension>
    </Extensions>

由于在后台任务中,是把用户在Toast通知上选择的项保存到本地文件中,所以在主应用中,可以读出文件的内容,并显示出来。

        protected override async void OnNavigatedTo(NavigationEventArgs e)
        {
            try
            {
                // 读入后台保存的内容
                StorageFolder local = ApplicationData.Current.LocalFolder;
                StorageFile dataFile = await local.GetFileAsync("data.json");
                if (dataFile == null) return;

                string jsstr = await FileIO.ReadTextAsync(dataFile, Windows.Storage.Streams.UnicodeEncoding.Utf8);

                JsonObject jsobj = null;
                if (JsonObject.TryParse(jsstr, out jsobj))
                {
                    double d = jsobj.GetNamedNumber("updatetime");
                    tbResultFromBackActivate.Text = $"你选择了每隔{d:N0}天更新一次。";
                }
                await dataFile.DeleteAsync();
            }
            catch(Exception ex)
            {
                Debug.WriteLine($"文件读取异常:{ex.Message},异常类型:{ex.GetType().Name}。");
            }

        }

最后,我们实现显示Toast通知的代码。

            string visual = "<visual>" +
                                "<binding template=\"ToastGeneric\">" +
                                    "<text>无敌应用</text>" +
                                    "<text>请选择更新间隔天数。</text>" +
                                "</binding>" +
                            "</visual>";
            string actions = "<actions>" +
                                "<input id=\"ut\" type=\"selection\" defaultInput=\"5\">"+
                                    "<selection id=\"3\" content=\"3天\" />" +
                                    "<selection id=\"5\" content=\"5天\" />" +
                                    "<selection id=\"10\" content=\"10天\" />" +
                                "</input>" +
                                "<action content=\"是\" activationType=\"background\" arguments=\"yes\" />" +
                                "<action content=\"否\" activationType=\"background\" arguments=\"no\" />" +
                            "</actions>";
            string toastXml = $"<toast>{visual}{actions}</toast>";

            XmlDocument doc = new XmlDocument();
            doc.LoadXml(toastXml);
            ToastNotification notification = new ToastNotification(doc);
            ToastNotifier notifier = ToastNotificationManager.CreateToastNotifier();
            notifier.Show(notification);

input元素的type为selection,表示Toast通知上的输入行为为列表选择,并使用三个selection元素定义了三个选项。注意,在input元素中,defaultInput属性指定输入控件的默认值。如果type为text,该属性设置默认的文本;在本例中,type为selection,所以默认值就是希望默认被选中的项的id值

似乎一切就绪了,实际上我们还有很关键一步没有做——注册后台任务,清单文件中仅仅是声明,而要希望让Toast通知的操作激活后台任务,还需要对后台任务进行注册。

        private async void RegToastBackgroundTask()
        {
            // 判断一下是否允许访问后台任务
            var res = await BackgroundExecutionManager.RequestAccessAsync();
            if (res == BackgroundAccessStatus.Denied || res == BackgroundAccessStatus.Unspecified)
            {
                return;
            }

            Type taskType = typeof(BackgroundTasks.ToastBgTask);
            var task = BackgroundTaskRegistration.AllTasks.Values.FirstOrDefault(t => t.Name == taskType.Name);
            if (task == null)
            {
                // 注册后台任务
                BackgroundTaskBuilder bd = new BackgroundTaskBuilder();
                bd.Name = taskType.Name;
                bd.TaskEntryPoint = taskType.FullName;
                // 声明触发器
                ToastNotificationActionTrigger trigger = new ToastNotificationActionTrigger();
                bd.SetTrigger(trigger);
                task = bd.Register();
            }
        }

后台的触发器便用 ToastNotificationActionTrigger类型。

现在我们来看一下,运行程序,等Toast通知出现后,把程序关了。然后在Toast通知上选择一个项,然后提交。

然后再次启动应用程序,可以看到结果了。

如何,这Win10的Toast通知是不是很牛X呢。由于小妹妹正在拿着我的920玩,所以就不用手机运行了,手机模拟器没有安装,大伙儿有兴趣的可以耍耍。

示例源码:http://files.cnblogs.com/files/tcjiaan/toastActivationApp.zip

时间: 2024-10-10 16:17:26

【Win 10 应用开发】Toast通知激活应用——前台&后台的相关文章

【Win 10 应用开发】打印UI元素

原文:[Win 10 应用开发]打印UI元素 Windows App支持将UI界面进行打印的功能,这与浏览器中的打印网页的用途相近,其好处就是“所见即所得”,直接把界面上呈现的内容打印下来,比重新创建打印图像方便得多. 要在通用App中实现打印,主要依靠以下几个类型: PrintManager:位于Windows.Graphics.Printing命名空间,主要负责显示打印对话框,设置打印源等操作.在使用时,首先调用GetForCurrentView静态方法得到一个PrintManager实例:

【Win 10应用开发】如何知道当前APP在哪个平台设备上运行

[Win 10应用开发]如何知道当前APP在哪个平台设备上运行 在做Win10开发的时候,我们可能经常会需要获得当前程序在在哪个平台设备上运行,用于UI和相关API的调用,那么可以通过什么方式知道当前APP运行的平台呢? 今天这里提供两个方法给大家做参考: 方法一:DeviceFamily 通过Windows.System.Profile.AnalyticsInfo.VersionInfo.DeviceFamily,来获取当前的平台设备,目前只可以得到两个值Windows.Mobile或Wind

【Win 10应用开发】实现全屏播放的方法

原文:[Win 10应用开发]实现全屏播放的方法 有人会问,以前的MediaElement控件不是有现成的一排操作按钮吗?而且可以直接进入全屏播放.是的,我们知道,以往的Store App都是在全屏模式下运行的,只要MediaElement控件填满整个窗口,就等于全屏播放了,但是,Win10应用是窗口化的,将MediaElement控件的IsFullWindow属性设置为true后,就会这样: 从上面的截图看,MediaElement控件只是覆盖整个窗口而已,并没有实现全屏.那有办法让它全屏播放

【Win 10应用开发】如何知道UAP在哪个平台上运行

原文:[Win 10应用开发]如何知道UAP在哪个平台上运行 面向22世纪的现代化应用程序可以同时在多种设备上运行,于是有朋友会有一个疑问:有时候,我们还真的需要判断一下,UAP应用程序在哪个平台上运行.尽管大多情况下我们不必要这样做,但某些特殊情况还得考虑.比如一串数据列表,我希望如果在桌面上运行时就以横向列表展现:但要是运行在手机上就以纵向列表展现. 也就是说,其实我们只需分析两种情况即可: 一.桌面.(台式机.笔记本.平板.游戏机.发广告专用机.导航器……) 二.移动环境.其实就是手机.

【Win 10 应用开发】RTM版的UAP项目解剖

原文:[Win 10 应用开发]RTM版的UAP项目解剖 Windows 10 发布后,其实SDK也偷偷地在VS的自定义安装列表中出现了,今天开发人员中心也更新了下载.正式版的SDK在API结构上和以前预览的时候是一样的,只是版本变成10240罢了,所以大家不要问老周有什么新的API. API虽然没变,但VS中的应用程序项目是有了新变化.毕竟以前都是预览的,而现在是“正规军”,以前练兵时都用土豆枪,现在都是真刀真枪干了,故而应用程序项目是有变化的. 以前老周跟大家讲的修改项目模板,去掉遥测类库的

【Win 10应用开发】Adaptive磁贴模板的XML文档结构

在若干天之前,老周给大家讲了Adaptive Toast通知的XML模板,所以相应地,今天老周给大家介绍一下Adaptive磁贴的新XML模板. 同样道理,你依旧可以使用8.1时候的磁贴模板,在win 10的API中也是支持的,此外,Win10 App还支持全新的自适应磁贴模板,本文老周就给大家先讲一下基本结构,下一篇文章中咱们再说一说复杂排版. 应用程序的图标可以分为两类:第一类是应用商店上专用的,就是你的应用提交到商店后,给用户看的图标:另一类就是应用本身的一些图标或磁贴. 磁贴其实也就这么

【Win 10应用开发】延迟共享

延迟共享是啥呢,这么说吧,就是在应用程序打开共享面板选择共享目标时,不会设置要共享的数据,而是等到共享目标请求数据时,才会发送数据,而且,延迟操作可以在后台进行. 这样说似乎过于抽象,最好的诠释方法,还是通过实例对比来观察吧. 老周设计的示例解决方案包含三个项目,其中一个是共享目标,用来接收共享的文本内容,并把文本写入到一个.txt文件中,存放到“文档”库中. 另外两个项目是:一个是未延迟的共享行为,再一个是延迟共享行为. 下面来对比一下效果. 先看未延迟共享的操作,如下图. 因为我在发送数据前

【Win 10 应用开发】启动远程设备上的应用

这个功能必须在“红石-1”(build 14393)以上的系统版中才能使用,运行在一台设备上的应用,可以通过URI来启动另一台设备上的应用.激活远程应用需要以下前提: 系统必须是build 14393或以上版本,UWP应用必须使用14393或以上版本的SDK开发. 被启动的应用应当支持协议激活,比如Cortana的协议URI为:[ms-cortana:],当然如果是你自己开发的应用,可以自己定义一个协议,名字随便取,不要跟系统的协议或别人的应用冲突就行,比如:[haha:][zxzx:]等. 必

【Win 10 应用开发】导入.pfx证书

这个功能其实并不常用,一般开发较少涉及到证书,不过,简单了解一下还是有必要的. 先来说说制作测试证书的方法,这里老周讲两种方法,可以生成用于测试的.pfx文件. 产生证书,大家都知道有个makecert工具.好,我们先用这个工具来生成一个证书,并存放到当前用户的证书存储中.打开VS的开发人员命令提示符,然后输入: makecert -n "CN=中国好男人" -pe -sr CurrentUser -ss My -b 01/01/2016 -e 12/31/2018 -n 表示证书的标