上一篇提到Windows Store協議的使用,其實Windows Store協議僅是系統內建的一種協議規則。我們也可以自己定義一套規范的URI-Scheme,除了可以給其他App調用外,本應用也可以進行調用,解決一些特殊的場景,本講具體探討這一問題。
關於Windows Store協議的解析和使用,可先閱讀上一篇:http://www.cnblogs.com/zhxilin/p/4819372.html
一.自定義協議的處理
前面提到,通過協議,應用可以被“激活(Activated)”,並且可以自行處理激活之后的操作。應用商店這個App的原理很簡單,它在Package.appxmanifest里定義了一個“協議”類型的聲明叫ms-windows-store,我們可以模擬一下:
由於ms-windows-store被定義為內建的協議,我們自定義協議時並不能使用這個名稱,這里用ms-windows-store1代替。
關於更多內建協議的使用規則,請參考:https://msdn.microsoft.com/en-us/library/windows/apps/mt228340.aspx
回到App.cs里,重載OnActivated方法,該方法接收一個IActivatedEventArgs類型的參數:
1 protected override async void OnActivated(IActivatedEventArgs args) 2 { 3 // TODO: handle activate action 4 }
通過args參數的Kind屬性來確定具體是哪種類型激活了應用,我們這里只處理Protocol類型的激活(因為自定義協議就是一種Protocol):
1 protected override async void OnActivated(IActivatedEventArgs args) 2 { 3 if (args.Kind == ActivationKind.Protocol) 4 { 5 if (!_hasLaunched) 6 { 7 CreateRootFrame(); 8 _hasLaunched = true; 9 } 10 11 var protocalArgs = (ProtocolActivatedEventArgs) args; 12 if (protocalArgs.Uri.Scheme == AppConfig.MyAppScheme) 13 { 14 UrlSchemeHelper.ParseScheme(protocalArgs.Uri); 15 } 16 } 17 Window.Current.Activate(); 18 }
確定了屬於協議激活后,將args轉成對應類型的參數ProtocolActivatedEventArgs,最終我們如同處理一個普通http url一樣,自定義個一個UrlSchemeHelper類進行解析和頁面導航,具體處理請自行腦洞。
二.自定義協議的意義
自定義協議,對呼叫協議作不同的響應,這是一件非常酷的事情。不僅可以給第三方應用調用,還可以給應用本身調用,處理一些特殊場景!我這里要說的一個特殊的適用場景就是App和Web頁面的交互。
App和Web頁面的交互是非常普遍的情景,一般頁面都會考慮直接使用腳本進行通知,並且我相信絕大部分前端開發者都已經被逼瘋:WP需要一種處理,iOS又是另一種處理;前端得判斷請求來自什么平台,而且還不准確,BlaBla....總之問題非常多!
現在有這樣一個需求,比如在一個Web頁面里有一個按鈕,觸發了這個按鈕之后要求App跳轉到某一個指定頁面,通常寫個腳本的話應該是這樣的(UWP應使用window.external.notify("")函數,且只能返回字符串)
1 function onNavigateClick() { 2 window.external.notify("navigate:some_page"); 3 }
App在WebView上注冊void Browser_ScriptNotify(object sender, NotifyEventArgs e)事件,通過參數e.Value將web頁面的通知內容“navigate:some_page”取出來做相應處理。
然而ScriptNotify事件的局限性非常大:
1.window.external.notify只能返回字符串
2.只有本地的Web頁面(ms-appdata、ms-local-stream或ms-appx-web),或者受信任的HTTPS才能觸發事件;普通HTTP無法觸發
大多數Web頁面都是HTTP的,並且如果下載到本地再顯示往往有問題,因此對UWP來說,這種交互方式簡直就是噩夢!不僅前端痛苦,客戶端也痛苦!
這時候自定義協議就可以發揮其功力了!同樣的例子,現在完全可以改成協議的形式來進行通知:
1 function onNavigateClick() { 2 window.location.href = 'myapp://page?id=1&title=hero'; 3 }
App里就用上述提到的方式接收通知!
且慢,在UWP項目中,在一個WebView里,某一個html頁面通過自定義的URI-Scheme的形式來通知APP時,WebView會觸發一個UnsupportedUriSchemeIdentified事件,表示WebView並不認識這個協議,是否要處理取決於你。
UWP的WebView默認只能處理http, https, ms-appx-web和ms-local-stream這幾種協議,對於其他協議,都會觸發UnsupportedUriSchemeIdentified事件,並且會彈出一個警告對話框:
為了不顯示這個對話框,我們需要手動處理一下:
1 private async void WebView_OnUnsupportedUriSchemeIdentified(WebView sender, WebViewUnsupportedUriSchemeIdentifiedEventArgs args) 2 { 3 args.Handled = true; 4 if (args.Uri.Scheme == AppConfig.MyAppScheme) 5 { 6 await Launcher.LaunchUriAsync(args.Uri); 7 } 8 }
先將args.Handled標記為true,警告對話框就不會彈出了;然后再通過Launcher嘗試啟動這個WebView不識別的URI;最后用我們上述講到的處理方式在App.OnActivated中接收並解析。
這樣的好處完全解放了前端開發的壓力,這套機制適用於各種各樣的客戶端(iOS、Android、WP、Windows等);對於客戶端而言,定義規范化的URI-Scheme有助於維護和擴展,甚至可以發展成開發平台或開放應用(如同商店APP一樣)。