【Win10 UWP】URI Scheme(二):自定义协议的处理和适用场景

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

posted @ 2015-09-30 15:32 zhxilin 阅读(...) 评论(...) 编辑 收藏