Windows phone 应用开发[14]-调用WebBrowser

很久没有更新博客了.最近一直陷身在项目中难以有时间抽身梳理总结.关于博客确实很多想写的主题.节前大概草草 的梳理一下大概就有十几个主题.只能趁着放假的时间来逐渐把这批文章力所能及系统的更新出来. 主要涉及到我们团队现在Windows phone 项目开发中实际碰到一些问题和对应解决方案.如果想关注即时了解每天动态信息可以直接在Sina微博@chenkaiHome 沟通交流.

在开始更新这批博文前.一直在顾虑先更新那个主题为好.回头一想索性就说说这半个月有些苦恼的Windows phone中处理 WebBrowser在我们项目中表现出来问题.

话说去年.技术团队提出要优化产品在各个平台[IOS/Android/WP7/QT]客户端开发业务流程.提出这个问题主要是为了把原来通用业务逻辑流程封装到能力更大的服务器端来做.各个客户端在通过WebView统一的形式调用.这样做目的.主要是解决原来各个客户端在业务升级后更新客户端版本时减少重新开发量.这样一来把核心的业务逻辑变动全部集中服务器端.需求变化自上而下传递过程中.在各个平台之间可以复用. 在每次更迭客户端版本时提升开发团队效率.

最开始我们采用的方案焦点主要是考虑到WebView封装通用的业务逻辑流程涉及到与对应平台原生应用程序的交互问题上.所以也就理所当然有人提出跨平台移动框架PhoneGap[平台交互]+HTML 5[UI呈现]的处理方案. 原来我们设想真的很简单.也天真的认为PhoneGap+HTML 5搭配会把通用业务流程问题迎刃而解.

首先.PhoneGap[PS参考:Windows phone 应用开发[8]-体验PhoneGap]作为移动跨平台框架.着重解决的问题是通过JavaScript实现跨平台API交互.并没有UI.页面还需要借助HTML 5效果.即使如此.也是难以和原生应用程序界面相媲美的.这就需要在使用过程中.要牺牲掉大量原生应用程序交互细节.用户体验上打了一个折扣.当然这和我们解决的核心问题做出牺牲还是值得.但问题各个平台兼容性需要调整各个平台适配问题大大出乎我们预估.而在性能差异上更是难以兼顾保证的.而对于初次使用PhoneGap团队解决这些问题所耗费的开发周期时间.却远大于开发Native Application原生应用时间还要长.这完全和使用初衷相背离. 其实问题只是换了一种形式存在. 我们只是从一个熟悉能够预估量的泥潭跳到另外完全未知泥潭中.不断尝试挣扎…

谈到这.说一个细节.类似在WebBrowser浏览器控件中.打开一个新窗口的问题.Android平台可以采用LoadUrl方法直接打开一个新窗体实现Js控制的页面跳转. 而目前Windows phone WebBrowser情况不支持在当前页打开新窗体.虽然可以通过InvokeJavaScript()放在LoadComplated方法中注入Js控制方法替换打开方式来实现. 但在实际调试中会发现.开发人员在C# 后台代码中调试JavaScript来说是一个挑战. 一来WebBrowser在注入和执行Js过程返回的错误或异常都是简单的代码80开头Code.而没有具体的堆栈信息. 这对找错和确认问题照成很大障碍.另外在C#后台代码处理JS缺乏有效的调试工具支持.这对PhoneGap封装出来页面复杂的Js调用或数据交互操作.照成一定难题.

说白了.在PhoenGap中通过JS实现Windows phone应用平台交互主要体现在两个点上.第一就是通过在Js中调用:

【JAvaScript:】

window.external.Notify(“”);

方法把页面交互数据通过WebBrowser控件SCriptNotify事件接收传递给原生应用程序. 另外一个点.就是可以在在Windows phone应用程序直接调用WEbBrowser控件InvokeScript()方法来调用JavaScript函数. 这两个方法.实现了PhoneGap数据传递和交互整个过程.

2012-04-03_233226

那在Windows phone应用程序使用WebBrowser有哪些常见需要解决的问题?

[1]异常处理.

well.这里不得不首先说在WebBrowser调用JavaSCript时需要处理的异常问题.Windows Phone 提供一个基于桌面版本的 Silverlight 的 WebBrowser 控件,也就是说WindowsPhone 目前的WEbBrowser控件是基于Silverlight桌面版本的WebBrowser控件而来,但仍然有几处不同[WEbBrowser与Silverlight版本不同地方].其中两个版本在开发最大不同主要有如下几点:

Windows phone WebBrowser控件与Silverlight 桌面版本的不同:

[1]Windows phone 版本相对Silverlight版本具有直接使用 IsolateStroage独立存储的权限

[2]相对Silverlight在执行InvokeScript()方法时限制了执行范围必须是XAP 程序包相同的站点中加载的脚本.而Windows phone 解除该限制.

[3]在Windows phone版本时从独立存储加载的内容或使用 NavigateToString(String) 方法加载的内容没有跨站点访问限制。

那么在Windows phone WebBrowser中调用JavaScript常见的可能出现的异常主要有两个,如下重现这两个异常情况.首先创建一个Windows Phone Application 应用程序. Mainpage.CS:

 1: <!--ContentPanel - place additional content here-->
 2: <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
 3:  <StackPanel>
 4:  <phone:WebBrowser x:Name="ComponentContent_WB" Height="450"/>
 5:  <Button x:Name="ExcuteScript_BT" Content="Excute JavaScript" Margin="0,50,0,0" Click="ExcuteScript_BT_Click"></Button>
 6:  </StackPanel>
 7: </Grid>

定义一个WebBrowser和Button按钮用来在页面加载完成后执行JavaSCripti函数事件.当然在执行JavaSCript需要设置WEbbrowser可以调用JS的. 设置IsScriptEnabled="True" BehindCode 如下:

 1:  // Constructor
 2:  public MainPage()
 3:  {
 4:  InitializeComponent();
 5:  this.Loaded += new RoutedEventHandler(MainPage_Loaded);
 6:  }
 7:  
 8:  void MainPage_Loaded(object sender, RoutedEventArgs e)
 9:  {
 10:  string navigateUrl = @"http://www.163.com";
 11:  this.ComponentContent_WB.Navigate(new Uri(navigateUrl, UriKind.RelativeOrAbsolute));
 12:  }
 13:  
 14:  private void ExcuteScript_BT_Click(object sender, RoutedEventArgs e)
 15:  {
 16:  //Button Client Event Excute InvokeJavaScript Method
 17:  try
 18:  {
 19:  this.ComponentContent_WB.InvokeScript("DefineNoExistJSMethod");
 20:  }
 21:  catch (Exception se)
 22:  {
 23:  MessageBox.Show("Excute JavaScript Have Exception:" + se.Message);
 24:  }
 25:  }

调用通用网易站点.在加载页面完成后通过Button按钮执行一个不来就不存在JavaScript函数.执行效果如下":

2012-04-04_151451

因这个JavaScript函数不存在所以执行肯定报错.注意这里报错信息是以80020006为开头的UnKnowError如下:

2012-04-04_152050

可见在堆栈的异常信息一栏中对JavaScripit提供的信息非常有限.这个Message代码为80020006.其实就是在当前应用程序执行范围找不到该JavaScript方法.另外一种情况恰恰相反.在执行已经定义JavaScript Function 函数出现的异常. 类似找到163.com站点中一个任意JAvaScript函数在后台方法调用:

 1:  function NTESAutoComplete ( inputElem, nextElem ) {
 2:  var t = this;
 3:  t._inputElem = inputElem;
 4:  t._nextElem = nextElem;
 5:  t._idName = "login_auto_list";
 6:  t._className = "login-auto-list";
 7:  }

注意InvokeScript方法在执行带有JAvaScript参数时. 参数传递是以String[]数组方式传递给JAvaScript函数.调用:

 1:  private void ExcuteScript_BT_Click(object sender, RoutedEventArgs e)
 2:  {
 3:  //Button Client Event Excute InvokeJavaScript Method
 4:  try
 5:  {
 6:  this.ComponentContent_WB.InvokeScript("NTESAutoComplete",new string[]{"NoExistElement",
 "NoExistStringArgument"});
 7:  }
 8:  catch (Exception se)
 9:  {
 10:  MessageBox.Show("Excute JavaScript Have Exception:" + se.Message);
 11:  }
 12:  }

执行效果如下:

2012-04-04_162830

执行过程中InvokeScript得到异常 "An unknown error has occurred. Error: 80020101".而这个异常是在往往执行过程JavaScript内部错误引起.因在后台代码没有有效的工具.支持.所以对于JavaScript的错误是很难查找确认问题具体在那. 这个问题出现一般会有两种大概原因.

第一点.在调用InvokeScript()是WebBrowser控件事件执行顺序.其实针对WEbBrowser控件.除了从FrameworkElement类和Control类继承了通用了UIElement属性和方法外.WEbBrowser重点扩展自身导航操作.类似其中三个比较中重要的方法.Navigating、Navigated 和 LoadCompleted事件.

那么说到这 这个三个事件在实际操作执行顺序是?

WebBrowser导航事件的执行顺序:

Navigating > Navigated > LoadCompleted

Navigating是执行Navigate方法表示当前WEbBrowser正在执行加载URL操作、Navigated事件WebBrowser 控件成功导航后发生 和 LoadCompleted事件在 WebBrowser 控件成功加载内容后发生.

如果在这种情况下.即使我们发现我们Codebehind中InvokeScript()调用JS没有问题.同时HTML JavaScript函数测试也没有问题.这就导致我们始终无法通过程序测试找到JS 报错80020101异常在那. 这是在后台代码调试JAvaScript最让人痛苦的地方.比如我们在如下方法掉用如上JavaScript函数:

 void Wb_Navigated(object sender, System.Windows.Navigation.NavigationEventArgs e)
 {
 Wb.InvokeScript("eval", "document.forms[0].submit();"); // Throws 80020101
 }
 
 private void MainPage_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
 {
 Wb.InvokeScript("eval", "document.forms[0].submit();"); // Works
 }

可以发现.如果在Navigated事件触发时.即使我们后台代码调用和JavaScript函数都没有错误.依然还是爆出80020101的异常.这主要是因为DOM对象操作在页面触发Navigated事件还没有完全初始化.导致调用页面执行时出现异常.

第二点.则是比较常见的即使需要对JavaSCript做一定修改.确保JS函数在执行时不会出错. 则这个80020101异常一般都会在如上两种情况下出现.

[2]现实静态页面.

在WEbBrowser中.可能需要在没有网络情况下.需要在某一些情况下通过后台应用程序操作HTML页面. 而在Windows phone提供两种方式来加载本地静态的HTML页面.

在Windows phone 中WEbBrowser中提供NavigateToString方法将 HTML 字符串置于 Web 浏览器控件中以便进行呈现.操作也是简单的:

 1:  string defineHtmlStr = @"<html>
 2:  <head>
 3:  <script>
 4:  function DefineExistFun(elementStr)
 5:  {
 6:  var getElems=document.getElementByTag(elementStr);
 7:  alert(elementStr);
 8:  }
 9:  </script>
 10:  <body>
 11:  <a href=" + "http://chenkai.cnblogs.com" + ">Test</a>"
 12:  + "</body>"
 13:  + "</head></html>";
 14:  this.ComponentContent_WB.NavigateToString(defineHtmlStr);

加载页面效果:

2012-04-04_171035

另外一种方式.则是加载一定定制好静态HTML页面.使用 WebBrowser 控件在应用程序中显示已设置格式的静态内容。例如,开发人员可能希望在应用程序包中包含帮助文本,以便用户可以随时访问.创建一个静态HTML界面:

 1: <html>
 2: <head>
 3: <script>
 4:  function DefineExistFun(elementStr)
 5:  {
 6:  var getElems=document.getElementByTag(elementStr);
 7:  alert(elementStr);
 8:  }
 9: </script>
 10: <body>
 11: <a href="http://chenkai.cnblogs.com">Test</a>
 12: </body>
 13: </head>
 14: </html>

在执行第一步需要把该CreateProduct.html页面添加解决方案.设置引用资源为Content.需要向独立存储中添加存储静态文件.:

 1:  private void SaveFilesToIsoStore()
 2:  {
 3:  //These files must match what is included in the application package,
 4:  //or BinaryStream.Dispose below will throw an exception.
 5:  string[] files = {
 6:  "CreateProduct.html"
 7:  };
 8:  
 9:  IsolatedStorageFile isoStore = IsolatedStorageFile.GetUserStoreForApplication();
 10:  
 11:  if (false == isoStore.FileExists(files[0]))
 12:  {
 13:  foreach (string f in files)
 14:  {
 15:  StreamResourceInfo sr = Application.GetResourceStream(new Uri(f, UriKind.Relative));
 16:  using (BinaryReader br = new BinaryReader(sr.Stream))
 17:  {
 18:  byte[] data = br.ReadBytes((int)sr.Stream.Length);
 19:  SaveToIsoStore(f, data);
 20:  }
 21:  }
 22:  }
 23:  }
 24:  
 25:  private void SaveToIsoStore(string fileName, byte[] data)
 26:  {
 27:  string strBaseDir = string.Empty;
 28:  string delimStr = "/";
 29:  char[] delimiter = delimStr.ToCharArray();
 30:  string[] dirsPath = fileName.Split(delimiter);
 31:  
 32:  //Get the IsoStore.
 33:  IsolatedStorageFile isoStore = IsolatedStorageFile.GetUserStoreForApplication();
 34:  
 35:  //Re-create the directory structure.
 36:  for (int i = 0; i < dirsPath.Length - 1; i++)
 37:  {
 38:  strBaseDir = System.IO.Path.Combine(strBaseDir, dirsPath[i]);
 39:  isoStore.CreateDirectory(strBaseDir);
 40:  }
 41:  
 42:  //Remove the existing file.
 43:  if (isoStore.FileExists(fileName))
 44:  {
 45:  isoStore.DeleteFile(fileName);
 46:  }
 47:  
 48:  //Write the file.
 49:  using (BinaryWriter bw = new BinaryWriter(isoStore.CreateFile(fileName)))
 50:  {
 51:  bw.Write(data);
 52:  bw.Close();
 53:  }
 54:  }

把需要展示的静态HTML页面在调用前需要存储到独立存储中.调用如下:

 1:  void MainPage_Loaded(object sender, RoutedEventArgs e)
 2:  { 
 3:  SaveFilesToIsoStore();
 4:  ComponentContent_WB.Navigate(new Uri("CreateProduct.html", UriKind.Relative)); 
 5:  }
成功加载的页面:

2012-04-04_171035

针对在Windows phone WEbBrowser中于JavaScript交付问题的问题出现的异常.在后台代码上处理是非常弱的.首先在CodeBehind中没有成行JS调试工具支持.这对不熟悉前段JavaSCript代码的开发人员来说是一个挑战. 另外一个问题就是一旦调用JavaScript出现异常情况.很难确认问题源头.这也大大影响开发效率.

当然在WEbBroser还涉及到页面加载控制. 新窗口打开. 控制WEbBrowser页面缩放等问题.这里就不再一一赘述.

关于本片源码详见:https://github.com/chenkai/WebBrowser-Case-Windows-phone-Sample

源码下载:/Files/chenkai/WebBrowserWP7Demo.rar

如有问题可以Weibo上沟通交流:http://weibo.com/chenkaihome

 

转载于:https://www.cnblogs.com/chenkai/archive/2012/04/04/2432120.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/475219.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

LeetCode 369. 给单链表加一(递归)

文章目录1. 题目2. 解题1. 题目 用一个 非空 单链表来表示一个非负整数&#xff0c;然后将这个整数加一。 你可以假设这个整数除了 0 本身&#xff0c;没有任何前导的 0。 这个整数的各个数位按照 高位在链表头部、低位在链表尾部 的顺序排列。 示例: 输入: [1,2,3] 输出: …

LeetCode 1430. 判断给定的序列是否是二叉树从根到叶的路径(递归)

文章目录1. 题目2. 解题1. 题目 给定一个二叉树&#xff0c;我们称从根节点到任意叶节点的任意路径中的节点值所构成的序列为该二叉树的一个 “有效序列” 。 检查一个给定的序列是否是给定二叉树的一个 “有效序列” 。 我们以整数数组 arr 的形式给出这个序列。 从根节点到…

LeetCode 362. 敲击计数器(map)

文章目录1. 题目2. 解题1. 题目 设计一个敲击计数器&#xff0c;使它可以统计在过去5分钟内被敲击次数。 每个函数会接收一个时间戳参数&#xff08;以秒为单位&#xff09;&#xff0c;你可以假设最早的时间戳从1开始&#xff0c;且都是按照时间顺序对系统进行调用&#xff…

a算法TSP旅行商java_A*算法实现旅行商问题(人工智能报告,付代码)

一、问题描述“旅行商问题”常被称为“旅行推销员问题”&#xff0c;是指一名推销员要拜访多个地点时&#xff0c;如何找到在拜访每个地点一次后再回到起点的最短路径。规则虽然简单&#xff0c;但在地点数目增多后求解却极为复杂。旅行商问题在本实验中的具体化&#xff1a;从…

windows phone 7 中文天气预报应用--来源http://www.cnblogs.com/liulunet/archive/2011/08/17/2141696.html...

windows phone 7 中文天气预报应用wp7的应用还是太少了&#xff0c;中文应用更少。虽然有天气预报应用但是自己感觉并不好用&#xff0c;感觉这样的程序应该很简单&#xff0c;于是萌生了自己写一个的想法。 印证了群里朋友说的一句话&#xff1a;程序员往往都是使用别人的程序…

LeetCode 666. 路径和 IV(树的遍历)

文章目录1. 题目2. 解题1. 题目 对于一棵深度小于 5 的树&#xff0c;可以用一组三位十进制整数来表示。 对于每个整数&#xff1a; 百位上的数字表示这个节点的深度 D&#xff0c;1 < D < 4。十位上的数字表示这个节点在当前层所在的位置 P&#xff0c; 1 < P <…

Prim最小生成树算法

在一个具有几个顶点的连通图G中&#xff0c;如果存在子图G包含G中所有顶点和一部分边&#xff0c;且不形成回路&#xff0c;则称G为图G的生成树&#xff0c;代价最小生成树则称为最小生成树。 许多应用问题都是一个求无向连通图的最小生成树问题。例如&#xff1a;要…

LeetCode 1214. 查找两棵二叉搜索树之和(二叉树迭代器+双指针)

文章目录1. 题目2. 解题1. 题目 给出两棵二叉搜索树&#xff0c;请你从两棵树中各找出一个节点&#xff0c;使得这两个节点的值之和等于目标值 Target。 如果可以找到返回 True&#xff0c;否则返回 False。 示例 1&#xff1a; 输入&#xff1a;root1 [2,1,4], root2 [1,…

LeetCode 323. 无向图中连通分量的数目(并查集)

文章目录1. 题目2. 解题1. 题目 给定编号从 0 到 n-1 的 n 个节点和一个无向边列表&#xff08;每条边都是一对节点&#xff09;&#xff0c;请编写一个函数来计算无向图中连通分量的数目。 示例 1: 输入: n 5 和 edges [[0, 1], [1, 2], [3, 4]]0 3| |1…

LeetCode 1120. 子树的最大平均值(DFS自底向上)

文章目录1. 题目2. 解题1. 题目 给你一棵二叉树的根节点 root&#xff0c;找出这棵树的 每一棵 子树的 平均值 中的 最大 值。 子树是树中的任意节点和它的所有后代构成的集合。 树的平均值是树中节点值的总和除以节点数。 示例&#xff1a;输入&#xff1a;[5,6,1] 输出&a…

LeetCode 1100. 长度为 K 的无重复字符子串(滑动窗口)

文章目录1. 题目2. 解题1. 题目 给你一个字符串 S&#xff0c;找出所有长度为 K 且不含重复字符的子串&#xff0c;请你返回全部满足要求的子串的 数目。 示例 1&#xff1a; 输入&#xff1a;S "havefunonleetcode", K 5 输出&#xff1a;6 解释&#xff1a; 这…

java点击按钮结线程_多线程的Java应用程序在调试工具Netbeans中单击“停止”按钮时输出一个奇怪的结果...

我使用wait()和notify()机制学习了java中的多线程。但我很好奇输出一个简单的多线程Java应用程序。代码如下&#xff1a;class Q {int n;boolean valueSet false;synchronized int get() {if (!valueSet) {try {wait();} catch (InterruptedException e) {System.out.println(…

LeetCode 544. 输出比赛匹配对(NBA季后赛对阵图)

文章目录1. 题目2. 解题1. 题目 在 NBA 季后赛中&#xff0c;我们总是安排较强的队伍对战较弱的队伍&#xff0c;例如用排名第 1 的队伍和第 n 的队伍对决&#xff0c;这是一个可以让比赛更加有趣的好策略。 现在&#xff0c;给你 n 支队伍&#xff0c;你需要以字符串格式输出…

LeetCode 1428. 至少有一个 1 的最左端列(二分查找)

文章目录1. 题目2. 解题2.1 二分查找2.2 直接走阶梯1. 题目 &#xff08;这是一个交互题&#xff09; 我们称只包含元素 0 或 1 的矩阵为二进制矩阵。 矩阵中每个单独的行都按非递减顺序排序。 给定一个这样的二进制矩阵&#xff0c;返回至少包含一个 1 的最左端列的索引&am…

LeetCode 370. 区间加法(差分思想)

文章目录1. 题目2. 解题1. 题目 假设你有一个长度为 n 的数组&#xff0c;初始情况下所有的数字均为 0&#xff0c;你将会被给出 k​​​​​​​ 个更新的操作。 其中&#xff0c;每个操作会被表示为一个三元组&#xff1a;[startIndex, endIndex, inc]&#xff0c;你需要将…

LeetCode 1256. 加密数字(bitset)

文章目录1. 题目2. 解题1. 题目 给你一个非负整数 num &#xff0c;返回它的「加密字符串」。 加密的过程是把一个整数用某个未知函数进行转化&#xff0c;你需要从下表推测出该转化函数&#xff1a; 示例 1&#xff1a; 输入&#xff1a;num 23 输出&#xff1a;"10…

java执行程序默认多线程吗_Java多线程 执行程序(1)

本文由作者收集整理所得&#xff0c;作者不保证内容的正确行&#xff0c;转载请标明出处。作者&#xff1a;关新全Java多线程执行程序(1)1.1Thread类static Thread.currentThread返回当前正在执行的线程对象的引用。join 等待线程终止。yield 暂停当前正在执行的线程对象&#…

LeetCode 531. 孤独像素 I

文章目录1. 题目2. 解题1. 题目 给定一幅黑白像素组成的图像, 计算黑色孤独像素的数量。 图像由一个由‘B’和‘W’组成二维字符数组表示, ‘B’和‘W’分别代表黑色像素和白色像素。 黑色孤独像素指的是在同一行和同一列不存在其他黑色像素的黑色像素。 示例: 输入: [[W,…

LeetCode 533. 孤独像素 II

文章目录1. 题目2. 解题1. 题目 给定一幅由黑色像素和白色像素组成的图像&#xff0c; 与一个正整数N, 找到位于某行 R 和某列 C 中且符合下列规则的黑色像素的数量: 行R 和列C都恰好包括N个黑色像素。列C中所有黑色像素所在的行必须和行R完全相同。 图像由一个由‘B’和‘W…

Windows 8桌面的尴尬

刚出炉的Windows8可谓荣宠极致&#xff0c;此时却被指出存在问题&#xff0c;面临失宠的尴尬。到底是什么问题呢&#xff1f; Windows 8中新的用户界面&#xff0c;已被完全证明是两级分化日益严重。  混合操作系统是一个新的GUI概念&#xff0c;友好地触摸界面接口&#xff…