天天看點

【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=重慶,然後按回車。應用程式啟動并接收資料。如下圖:

【Win 10開發】協定-上篇:自定義應用協定

好了,本文到此結束。

源碼下載下傳:https://files.cnblogs.com/files/tcjiaan/ProtocolApp.zip