zoukankan      html  css  js  c++  java
  • 【Win 10开发】协议-上篇:自定义应用协议

    就像系统许多内置应用可以通过URI来启动(如ms-settings-bluetooth:可以打开蓝牙设置页),我们自己开发的应用程序,如果需要的话,可以为应用程序自定义一个协议。应用程序协议在安装时会向操作系统注册,以后就可以直接通过URI来打开应用程序并传递相关的参数。

    本篇先介绍一下如何为应用程序注册自定义的协议。

    为应用程序注册协议是通过清单文件来完成的,清单文件位于项目中,一般的文件名为“Package.appxmanifest”,在创建应用程序项目时会自动创建该文件。如果你有兴趣的话的,可以把生成的清单文件删了,自己建一个,本质上就是一个XML文件,然后把文件的生成方式设置为AppxManifest就可以了。

    在预览版的SDK中只能手动写XML的方式来修改清单文件,相信在正式版发布后,VS会提供一个可视化的清单编辑器,毕竟VS的宗旨是解放生产力、发展生产力嘛。

    打开Package.appxmanifest文件后,找到Package / Applications / Application节,Application节点通常就是一个,因为大多数情况下,一个应用包中只有一个应用程序。在Application节点下输入以下XML:

          <Extensions>
            <!--配置协议-->
            <uap:Extension Category="windows.protocol">
              <uap:Protocol Name="emp"/>
            </uap:Extension>
          </Extensions>


    Extensions集合表示应用程序的扩展列表,比如像后台任务、后台音频、文件关联这些都属于应用扩展,Extensions下面可以包含N个Extension元素,而对于UAP应用,一定要用uap命名空间下的Extension元素,即http://schemas.microsoft.com/appx/manifest/uap/windows10命名空间。

    Protocol元素表示为应用程序定义的协议,Name特性指定协议的名字。这协议名可以自己定,但不要和系统的内置应用协议冲突就行。其实你也不用去记系统内置有哪些保留协议,只要你指定的协议名有问题,就会报错,那时候你自然会知道了。

    本例子中,我注册的协议名为emp,在调用应用程序时,只要执行这样的URI就可以了:emp:?a=b&c=d。

    协议名字后面记得跟着一个英文冒号,可以直接emp:就可以,?只是为了表示后那一串的参数,就像Web开发中的URI参数default.aspx?fuckID=366一样。

    当应用程序被协议激活后,Application实例的OnActivated方法会被调用,方法有一个参数:实现IActivatedEventArgs接口的类型实例。从方法参数的Kind属性可以判断应用程序是由于什么行为被激活的,因为应用程序不仅仅只有协议可以激活,通过文件关联等方式也可以激活应用程序,所以对Kind属性的判断是必须的。

    如果确定Kind属性是ActivationKind.Protocol,就说明应用程序就是通过协议激活的,此时可以将方法参数转换为ProtocolActivatedEventArgs来获取激活的URI。

    OnActived方法是虚的,所以其实是在App类中进行重写,然后根据传递过来的URI来做出相应的处理。本例中,分析URI中的参数,并将它们提取出来,显示到ShowDataPage页面上。

    URI参数一般是a=2这种用等号连接的键/值对,多项目参数用 & 符号来分隔。那么,怎么把这些参数项分析出来呢,我这里采用正则表达式的方式,提取key = value中的key值和vlaue值,而且它们可以多次出现(多项参数)。比如:

    a=2&b=3&c=4

    就可以提取出三项参数,并可以用字典数结构来封装:

    key= a,  value=2

    key= b,  value=3

    key=c ,  value = 4

    所以正则表达式中使用命名分组的方式就比较好,把参数名定义为key组,参数值为value组。正则如下:

    ((?<key>[^&=]+)=(?<value>[^&]+))+

    ?<key>[^&=]+表示参数名,排除&、=两个字符;

    ?<value>[^&]+表示参数值,排除&字符。

    因为&是参数连接符,不能出现在参数名和参数值中,对于参数值,也可以?<value>[^&]*,星号(*)允许出现0次,有可能参数值为空,但参数名肯定至少有一个字符的。

    相关的处理代码如下:

            protected override void OnActivated(IActivatedEventArgs args)
            {
                // 判断激类型
                if (args.Kind == ActivationKind.Protocol)
                {
                    ProtocolActivatedEventArgs parg = (ProtocolActivatedEventArgs)args;
                    // 获取激活URI
                    Uri activeUri = parg.Uri;
                    // 获取查询字符串
                    string qry = activeUri.Query;
                    // 去掉前面的“?”字符
                    qry = qry.Replace("?", "");
                    if (!string.IsNullOrEmpty(qry))
                    {
                        // 通过正则表达式来分析参数
                        System.Text.RegularExpressions.Regex rg = new System.Text.RegularExpressions.Regex("((?<key>[^&=]+)=(?<value>[^&]+))+");
                        var matches = rg.Matches(qry);
                        IDictionary<string, string> dicdata = new Dictionary<string, string>();
                        // 取出已匹配的内容
                        foreach (Match item in matches)
                        {
                            dicdata.Add(item.Groups["key"].Value, WebUtility.UrlDecode(item.Groups["value"].Value));
                        }
    
                        // 导航到显示内容的页面
                        Frame rootFrame = Window.Current.Content as Frame;
                        if (rootFrame == null)
                        {
                            rootFrame = new Frame();
                            Window.Current.Content = rootFrame;
                        }
                        rootFrame.Navigate(typeof(ShowDataPage), dicdata);
                    }
                }
    
                Window.Current.Activate();
            }

     由于URI在调用时可能会做URI编码处理,所以用上UrlDecode方法保险一些。

    分析URI得到的内容放到一个字典集合中,并在导航时作为参数传递给ShowDataPage页面,因此在ShowDataPage类中要重写OnNavigatedTo方法,并处理传递进来的参数。

            protected override void OnNavigatedTo(NavigationEventArgs e)
            {
                IDictionary<string, string> data = e.Parameter as IDictionary<string,string>;
                if (data != null)
                {
                    System.Text.StringBuilder strbd = new System.Text.StringBuilder();
                    foreach (var kv in data)
                    {
                        strbd.AppendLine(kv.Key + " : " + kv.Value);
                    }
                    tbData.Text = strbd.ToString();
                }
            }

    运行应用程序,可以打开浏览器,在地址栏中输入:emp:?name=小明&age=100&city=重庆,然后按回车。应用程序启动并接收数据。如下图:

    好了,本文到此结束。

    源码下载:http://files.cnblogs.com/files/tcjiaan/ProtocolApp.zip

  • 相关阅读:
    JS中的钩子(hook)机制与实现
    Java 之 注解的定义
    Java 网络编程案例:使用 MulticastSocket 实现多点广播
    Java 基于 UDP 协议的网络编程
    Java 网络编程案例四:多个客户端群聊
    Java 网络编程案例三:多个客户端上传文件
    Java 网络编程案例二:多台客户端与服务器之间的多次通信
    Java 网络编程案例一:一台客户端与服务器单次通信
    Java 之 网络常用API
    Java 之 网络编程基础知识
  • 原文地址:https://www.cnblogs.com/tcjiaan/p/4460560.html
Copyright © 2011-2022 走看看