上一篇提到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一样)。