目录
1. window.external.notify
2. Url
首页 web前端 html教程 为自己搭建一个鹊桥 Native Page与Web View之间的JSBridge实现方式_html/css_WEB-ITnose

为自己搭建一个鹊桥 Native Page与Web View之间的JSBridge实现方式_html/css_WEB-ITnose

Jun 21, 2016 am 08:52 AM

说起JSBridge,大家最熟悉的应该就是微信的WeixinJSBridge,通过它各个公众页面可以调用后台方法和微信进行交互,为用户提供相关功能。我们就来说说UWP下怎么样实现我们自己的JSBridge。

在win10之前,如果需要实现JSBridge,我们大概有两种方法:

1. window.external.notify

做过webview的小伙伴肯定都熟悉,html页面可以通过window.external.notify将消息发送出去,然后客户端使用WebView.ScriptNotify事件接收,但是两边都只能用字符串来交流,所以通常我们都会定义好消息格式(比如json)。现在在UWP中使用这种方法有个限制,就是你需要在.appxmanifest里把站点加到Content URIs中,告诉系统那些域名的js脚本是可以调用windows.external.notify方法的,当然如果是本地js就没有这个限制的,添加方法如下图。

但是我们总会有些特殊需求,比如微信/淘宝应用怎么办?域名随时可能增加,总不能每次都更新manifest,然后更新商店吧!在8.1的时候我们还可以使用WebView.AllowedScriptNotifyUris在应用中动态添加信任站点,但是win10中这个接口已经废弃了,如果你的应用并不需要频繁/动态更改信任站点,这个方法还是可用的。

后台处理完结果之后,可以通过WebView.InvokeScript/InvokeScriptAsync方法调用当前页面中的js方法:

第一个参数是js方法名,第二个参数是调用这个方法需要的参数。

需要注意的是这个方法很容易出错,一定要注意异常捕获:(, 而且生成的异常基本都是一些0xXXXXX的code。

 1     public sealed partial class MainPage : Page 2     { 3         BridgeObject.Bridge _bridge = new BridgeObject.Bridge(); 4  5         public MainPage() 6         { 7             this.InitializeComponent(); 8  9             this.wv.ScriptNotify += Wv_ScriptNotify;10 11             this.Loaded += MainPage_Loaded;12         }13 14         private async void Wv_ScriptNotify(object sender, NotifyEventArgs e)15         {16             await (new MessageDialog(e.Value)).ShowAsync();17 18             //返回结果给html页面19             await this.wv.InvokeScriptAsync("recieve", new[] { "hehe, 我是个结果"});20         }21 22         private void MainPage_Loaded(object sender, RoutedEventArgs e)23         {24             //我们事先写好了一个本地html页面用来做测试25             this.wv.Navigate(new Uri("ms-appx-web:///assets/html/index.html", UriKind.RelativeOrAbsolute));26         }27     }View Code
登录后复制

html代码:

 1 <!DOCTYPE html> 2  3 <html lang="en" xmlns="http://www.w3.org/1999/xhtml"> 4 <head> 5     <meta charset="utf-8" /> 6     <title></title> 7  8     <script> 9 10         //通知后台11         function func1()12         {13     14                 window.external.notify("this is a message");15             16         }17 18         //这个方法用来接收后台的结果19         function recieve(value)20         {21             output.textContent = value;22         }23 24     </script>25 </head>26 <body>27     <div style="margin-top:100px">28         <button id="fun1Btn" onclick="func1();">Call method 1</button>29         <div id="output"></div>30     </div>31 </body>32 </html>View Code
登录后复制

2. Url

是的,你没有看错,我们也可以通过url实现JSBridge,这也是我们在放弃上一种方法之后的一个备选方案,因为手淘就有之前说到的问题,站点可能不是固定的,而更新应用明显不是个明智的选择。具体就是每次html页面需要调用后台code的时候,都发起一次页面跳转,当然跳转的url符合一定的规则,并可以加上参数,然后我们用WebView.NavigationStarting事件截获这次跳转,并Cancel调这次跳转,这样一个看似可行的方案出炉啦,还是热乎的呢!!

代码其实很简单,就是解析url参数,然后再通过WebView.InvokeScript/InvokeScriptAsync方法返回结果给页面(这个方法不针对站点)。

 1         private void Wv_NavigationStarting(WebView sender, WebViewNavigationStartingEventArgs args) 2         { 3             if(args.Uri.OriginalString.StartsWith("http://our/jsbridge/url/pattern")) 4             { 5                 //是一次jsbridge调用,取消本次跳转 6                 args.Cancel = true; 7  8                 //这里具体解析url的参数 9             }10         }View Code
登录后复制

仔细想想。。好像也没什么不对,够动态,够简单。。。但现实总是残酷的,实际使用过程中突然发现,WebView的Url有最大长度限制,而且这个值比Android和IOS都要小很多,导致很多参数被截断了,最后只好放弃了。

就在上面两种方案都不能完美适应所有需求的时候,另外一种bulingbuling的方法出现在我们眼前: WebView.AddWebAllowedObject ,这个方法是win10中新添加的方法,允许我们把Windows Runtime对象直接传递给JS调用!

下面是这个方法的定义:

public void AddWebAllowedObject(string name, object pObject)

name 是对象在js中对应的全局变量名,通过这个方法传入到html页面中的对象都是挂在js的 window 对象上的, pObject 就是要传入的对象。

首先新建一个Windows Runtime Component工程,添加一个新的类Bridge,我们之后就把这个传给也main,看看这个类有什么特殊的。

 1     //这个attribute是必须的,有了他我们的对象才能传递给WebView 2     [AllowForWeb] 3     public sealed class Bridge 4     { 5         /// <summary> 6         /// 提示一条消息 7         /// </summary> 8         /// <param name="msg"></param> 9         public void showMessage(string msg)10         {11             new MessageDialog(msg).ShowAsync();12         }13 14 15     }View Code
登录后复制

一切的魔法都在AllowForWebAttribute这个特性上,有了它,我们的对象就可以传递给webview,但是这里有一点一定要万分小心,必须在NavigationStarting调用AddWebAllowedObject方法才可以!(我不会告诉你,我在DomLoaded事件里折腾了好久。。。)

 1     public sealed partial class MainPage : Page 2     { 3         BridgeObject.Bridge _bridge = new BridgeObject.Bridge(); 4  5         public MainPage() 6         { 7             this.InitializeComponent(); 8  9             this.wv.NavigationStarting += Wv_NavigationStarting;10 11             this.Loaded += MainPage_Loaded;12         }13 14         private void MainPage_Loaded(object sender, RoutedEventArgs e)15         {16             //我们事先写好了一个本地html页面用来做测试17             this.wv.Navigate(new Uri("ms-appx-web:///assets/html/index.html", UriKind.RelativeOrAbsolute));18         }19 20         private void Wv_NavigationStarting(WebView sender, WebViewNavigationStartingEventArgs args)21         {22             //OURBRIDGEOBJ这个是我们的对象插入到页面之后对象的变量名,这是一个全局变量,也就是window.OURBRIDGEOBJ23             this.wv.AddWebAllowedObject("OURBRIDGEOBJ", _bridge);24         }25     }View Code
登录后复制

现在是见证奇迹的时候了,来看看在js中怎么调用这个对象?(请忽略我这水平不怎么样的html code。。。)

 1 <!DOCTYPE html> 2  3 <html lang="en" xmlns="http://www.w3.org/1999/xhtml"> 4 <head> 5     <meta charset="utf-8" /> 6     <title></title> 7  8     <script> 9 10         function func1() {11             // 首先判断我们对象是否正确插入12             if (window.OURBRIDGEOBJ) {13                 //调用的我们消息函数14                 window.OURBRIDGEOBJ.showMessage("呵呵呵,我是个message");15             }16         }17     </script>18 </head>19 <body>20     <div style="margin-top:100px">21         <button id="fun1Btn" onclick="func1();">Call method 1</button>22     </div>23 </body>24 </html>View Code
登录后复制

代码都很直接,唯一需要说明的就是一定要注意js中调用方法时首字母都是小写(即使你在后台定义的首字母大写!当然这应该也是为了符合js的使用习惯),来看看结果。

当然如果它只有这点本事的话,并不会让人很激动,毕竟我们以前也可以做到。

继续之前,想想win10之前如果要通过jsbridge调用后台代码实现一个异步操作会怎么实现呢?

1). 首先我们的js调用和WebView.InvokeScript是分开,所以通常我们要为每一次js调用生成一个id

2). 后台完成操作之后,通过InvokeScript方法返回结果时,需要把本次调用id传回去,告诉页面这个哪次调用的结果

3). 然后js再根据这个id回调继续之前的操作。

但是现在我们可以抛弃那些繁琐的步骤了,我们的Windows Runtime Component支持异步(IAsyncAction/IAsyncOperation),而js又支持 Promise ,结合在一起,你懂的!

先给我们的类添加一个简单的异步方法。

 1     //这个attribute是必须的,有了他我们的对象才能传递给WebView 2     [AllowForWeb] 3     public sealed class Bridge 4     { 5         /// <summary> 6         /// 提示一条消息 7         /// </summary> 8         /// <param name="msg"></param> 9         public void showMessage(string msg)10         {11             new MessageDialog(msg).ShowAsync();12         }13 14         public Windows.Foundation.IAsyncOperation<int> giveMeAnObject(int num)15         {16             return Task.Run(async () =>17             {18                 //延迟3秒钟,模拟异步任务:)19                 await Task.Delay(3000);20 21                 return ++num;22             }).AsAsyncOperation();23         }24     }View Code
登录后复制

接下来我们在js端,用 promise.then 来等待结果。

 1 <!DOCTYPE html> 2  3 <html lang="en" xmlns="http://www.w3.org/1999/xhtml"> 4 <head> 5     <meta charset="utf-8" /> 6     <title></title> 7  8     <script> 9 10         function func1() {11             // 首先判断我们对象是否正确插入12             if (window.OURBRIDGEOBJ) {13                 //调用的我们消息函数14                 window.OURBRIDGEOBJ.showMessage("呵呵呵,我是个message");15             }16         }17 18         function func2() {19             if (window.OURBRIDGEOBJ) {20 21                 //对于js来说winrt的异步操作都会对应到promise上22                 var result = window.OURBRIDGEOBJ.giveMeAnObject(12);23 24                 // 等待结果25                 result.then(function (nextNum) {26                     // nextNum就是IAsyncOperation<int>的真正返回值27                     output.textContent = nextNum;28                 });29 30             }31         }32     </script>33 </head>34 <body>35     <div style="margin-top:100px">36         <button id="fun1Btn" onclick="func1();">Call method 1</button>37         <button id="fun2Btn" onclick="func2();">Call method 2</button>38         <div id="output" />39     </div>40 </body>41 </html>View Code
登录后复制

运行起来,等待3秒之后,结果出来了!

最后如果你觉得写component限制太多的话(继承都不让用。。),可以使用接口定义方法,然后在类库中实现这些方法也是一个不错的方案,下面是一个比较简单的实现供参考。

我们的jsbridge接口,包含我们准备提供的方法。

1     /// <summary>2     /// 用来定义JSBridge中实现的方法3     /// </summary>4     public interface IBridgeMethods5     {6         IAsyncOperation<int> GiveMmeAnObject(int num);7         void ShowMessage(string message);8     }View Code
登录后复制

修改我们的Bridge类,所有的方法都通过上面的接口来提供。

 1    //这个attribute是必须的,有了他我们的对象才能传递给WebView 2     [AllowForWeb] 3     public sealed class Bridge 4     { 5         private IBridgeMethods _methods = null; 6  7  8         /// <summary> 9         /// 提示一条消息10         /// </summary>11         /// <param name="msg"></param>12         public void ShowMessage(string msg)13         {14             _methods?.ShowMessage(msg);15         }16 17         public IAsyncOperation<int> giveMeAnObject(int num)18         {19             return _methods?.GiveMmeAnObject(num);20         }21 22         /// <summary>23         /// 初始化个方法的实现24         /// </summary>25         /// <param name="obj"></param>26         public void Init(IBridgeMethods obj)27         {28             _methods = obj;29         }30     }View Code
登录后复制
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

HTML容易为初学者学习吗? HTML容易为初学者学习吗? Apr 07, 2025 am 12:11 AM

HTML适合初学者学习,因为它简单易学且能快速看到成果。1)HTML的学习曲线平缓,易于上手。2)只需掌握基本标签即可开始创建网页。3)灵活性高,可与CSS和JavaScript结合使用。4)丰富的学习资源和现代工具支持学习过程。

HTML,CSS和JavaScript的角色:核心职责 HTML,CSS和JavaScript的角色:核心职责 Apr 08, 2025 pm 07:05 PM

HTML定义网页结构,CSS负责样式和布局,JavaScript赋予动态交互。三者在网页开发中各司其职,共同构建丰富多彩的网站。

了解HTML,CSS和JavaScript:初学者指南 了解HTML,CSS和JavaScript:初学者指南 Apr 12, 2025 am 12:02 AM

WebDevelovermentReliesonHtml,CSS和JavaScript:1)HTMLStructuresContent,2)CSSStyleSIT和3)JavaScriptAddSstractivity,形成thebasisofmodernWebemodernWebExexperiences。

HTML中起始标签的示例是什么? HTML中起始标签的示例是什么? Apr 06, 2025 am 12:04 AM

AnexampleOfAstartingTaginHtmlis,beginSaparagraph.startingTagSareEssentialInhtmlastheyInitiateEllements,defiteTheeTheErtypes,andarecrucialforsstructuringwebpages wepages webpages andConstructingthedom。

Gitee Pages静态网站部署失败:单个文件404错误如何排查和解决? Gitee Pages静态网站部署失败:单个文件404错误如何排查和解决? Apr 04, 2025 pm 11:54 PM

GiteePages静态网站部署失败:404错误排查与解决在使用Gitee...

网页批注如何实现Y轴位置的自适应布局? 网页批注如何实现Y轴位置的自适应布局? Apr 04, 2025 pm 11:30 PM

网页批注功能的Y轴位置自适应算法本文将探讨如何实现类似Word文档的批注功能,特别是如何处理批注之间的间�...

HTML,CSS和JavaScript:Web开发人员的基本工具 HTML,CSS和JavaScript:Web开发人员的基本工具 Apr 09, 2025 am 12:12 AM

HTML、CSS和JavaScript是Web开发的三大支柱。1.HTML定义网页结构,使用标签如、等。2.CSS控制网页样式,使用选择器和属性如color、font-size等。3.JavaScript实现动态效果和交互,通过事件监听和DOM操作。

如何用CSS3和JavaScript实现图片点击后周围图片散开并放大效果? 如何用CSS3和JavaScript实现图片点击后周围图片散开并放大效果? Apr 05, 2025 am 06:15 AM

实现图片点击后周围图片散开并放大效果许多网页设计中,需要实现一种交互效果:点击某张图片,使其周围的...

See all articles