目錄
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

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

<🎜>:泡泡膠模擬器無窮大 - 如何獲取和使用皇家鑰匙
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
北端:融合系統,解釋
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
Mandragora:巫婆樹的耳語 - 如何解鎖抓鉤
3 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Java教學
1666
14
CakePHP 教程
1425
52
Laravel 教程
1325
25
PHP教程
1272
29
C# 教程
1252
24
了解HTML,CSS和JavaScript:初學者指南 了解HTML,CSS和JavaScript:初學者指南 Apr 12, 2025 am 12:02 AM

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

HTML:結構,CSS:樣式,JavaScript:行為 HTML:結構,CSS:樣式,JavaScript:行為 Apr 18, 2025 am 12:09 AM

HTML、CSS和JavaScript在Web開發中的作用分別是:1.HTML定義網頁結構,2.CSS控製網頁樣式,3.JavaScript添加動態行為。它們共同構建了現代網站的框架、美觀和交互性。

HTML,CSS和JavaScript的未來:網絡開發趨勢 HTML,CSS和JavaScript的未來:網絡開發趨勢 Apr 19, 2025 am 12:02 AM

HTML的未來趨勢是語義化和Web組件,CSS的未來趨勢是CSS-in-JS和CSSHoudini,JavaScript的未來趨勢是WebAssembly和Serverless。 1.HTML的語義化提高可訪問性和SEO效果,Web組件提升開發效率但需注意瀏覽器兼容性。 2.CSS-in-JS增強樣式管理靈活性但可能增大文件體積,CSSHoudini允許直接操作CSS渲染。 3.WebAssembly優化瀏覽器應用性能但學習曲線陡,Serverless簡化開發但需優化冷啟動問題。

HTML的未來:網絡設計的發展和趨勢 HTML的未來:網絡設計的發展和趨勢 Apr 17, 2025 am 12:12 AM

HTML的未來充滿了無限可能。 1)新功能和標準將包括更多的語義化標籤和WebComponents的普及。 2)網頁設計趨勢將繼續向響應式和無障礙設計發展。 3)性能優化將通過響應式圖片加載和延遲加載技術提升用戶體驗。

HTML與CSS vs. JavaScript:比較概述 HTML與CSS vs. JavaScript:比較概述 Apr 16, 2025 am 12:04 AM

HTML、CSS和JavaScript在網頁開發中的角色分別是:HTML負責內容結構,CSS負責樣式,JavaScript負責動態行為。 1.HTML通過標籤定義網頁結構和內容,確保語義化。 2.CSS通過選擇器和屬性控製網頁樣式,使其美觀易讀。 3.JavaScript通過腳本控製網頁行為,實現動態和交互功能。

HTML:建立網頁的結構 HTML:建立網頁的結構 Apr 14, 2025 am 12:14 AM

HTML是構建網頁結構的基石。 1.HTML定義內容結構和語義,使用、、等標籤。 2.提供語義化標記,如、、等,提升SEO效果。 3.通過標籤實現用戶交互,需注意表單驗證。 4.使用、等高級元素結合JavaScript實現動態效果。 5.常見錯誤包括標籤未閉合和屬性值未加引號,需使用驗證工具。 6.優化策略包括減少HTTP請求、壓縮HTML、使用語義化標籤等。

HTML與CSS和JavaScript:比較Web技術 HTML與CSS和JavaScript:比較Web技術 Apr 23, 2025 am 12:05 AM

HTML、CSS和JavaScript是構建現代網頁的核心技術:1.HTML定義網頁結構,2.CSS負責網頁外觀,3.JavaScript提供網頁動態和交互性,它們共同作用,打造出用戶體驗良好的網站。

HTML:是編程語言還是其他? HTML:是編程語言還是其他? Apr 15, 2025 am 12:13 AM

HTMLISNOTAPROGRAMMENGUAGE; ITISAMARKUMARKUPLAGUAGE.1)htmlStructures andFormatSwebContentusingtags.2)itworkswithcsssforstylingandjavascript for Interactivity,增強WebevebDevelopment。

See all articles