码迷,mamicode.com
首页 > Web开发 > 详细

robotium原理之获取WebElement元素

时间:2015-07-07 21:22:14      阅读:239      评论:0      收藏:0      [点我收藏+]

标签:

robotium框架支持WebView,在robotium中有getWebElements()、getWebElements(By by)等方法来获取android中的WebView的元素,并提供了 clickOnWebElement方法来完成点击事件.android中的原生控件是比较好攻取的,那么对于WebView这个框架是怎么获取的呢。

第一步:利用JS获取页面中的所有元素 

         在PC上,获取网页的元素可以通过注入javascript元素来完成,以Chrome浏览器为例,打开工具——JavaScript控制台(快捷方式:Ctrl+Shift+J),输入 javascript:prompt(document.URL)即会弹出含当前页面的URL的提示框,因此通过编写适当的JS脚本是可以在这个弹出框中显示所有页面元素的。RobotiumWeb.js就是此功能实现用的JS脚本。以solo中getWebElements()为例,

[java] view plaincopy技术分享技术分享

  1. public ArrayList<WebElement> getWebElements(boolean onlySufficientlyVisible){  

  2.     boolean javaScriptWasExecuted = executeJavaScriptFunction("allWebElements();");  

  3.       

  4.     return getWebElements(javaScriptWasExecuted, onlySufficientlyVisible);  

  5. }  

[java] view plaincopy技术分享技术分享

  1. private boolean executeJavaScriptFunction(final String function){  

  2.     final WebView webView = viewFetcher.getFreshestView(viewFetcher.getCurrentViews(WebView.classtrue));  

  3.   

  4.     if(webView == null){  

  5.         return false;  

  6.     }  

  7.                //做一些JS注入执行前的准备工作,例如将WebView设为可允许执行JS等,并将RobotiumWeb.js中的脚本以String形式返回  

  8.     final String javaScript = prepareForStartOfJavascriptExecution();  

  9.   

  10.     activityUtils.getCurrentActivity(false).runOnUiThread(new Runnable() {  

  11.         public void run() {  

  12.             if(webView != null){  

  13.                 webView.loadUrl("javascript:" + javaScript + function);  

  14.             }  

  15.         }  

  16.     });  

  17.     return true;  

  18. }  

        可以看出这个方法执行的是allWebElements();函数,即类似执行RobotiumWeb.js文件中如下JS代码片段:

可以把如下片段放到JavaScript控制台中看效果

[javascript] view plaincopy技术分享技术分享

  1. javascript:  

  2. function allWebElements() {  

  3.     for (var key in document.all){  

  4.         try{  

  5.             promptElement(document.all[key]);   //调用promptElement(element)函数          

  6.         }catch(ignored){}  

  7.     }  

  8.     finished();    //执行完后,调用finished()函数  

  9. }  

  10.   

  11. function promptElement(element) {  

  12.     var id = element.id;  

  13.     var text = element.innerText;  

  14.     if(text.trim().length == 0){  

  15.         text = element.value;  

  16.     }  

  17.     var name = element.getAttribute(‘name‘);  

  18.     var className = element.className;  

  19.     var tagName = element.tagName;  

  20.     var attributes = "";  

  21.     var htmlAttributes = element.attributes;  

  22.     for (var i = 0, htmlAttribute; htmlAttribute = htmlAttributes[i]; i++){  

  23.         attributes += htmlAttribute.name + "::" + htmlAttribute.value;  

  24.         if (i + 1 < htmlAttributes.length) {  

  25.             attributes += "#$";  

  26.         }  

  27.     }  

  28.   

  29.     var rect = element.getBoundingClientRect();  

  30.     if(rect.width > 0 && rect.height > 0 && rect.left >= 0 && rect.top >= 0){  

  31.         prompt(id + ‘;,‘ + text + ‘;,‘ + name + ";," + className + ";," + tagName + ";," + rect.left + ‘;,‘ + rect.top + ‘;,‘ + rect.width + ‘;,‘ + rect.height + ‘;,‘ + attributes);   //弹出包含id、text、name等字段的提示框  

  32.     }  

  33. }  

  34. function finished(){  

  35.     prompt(‘robotium-finished‘);    //弹出包含robotium-finished字符串的提示框,用于标识脚本注入执行结束  

  36. }  


        从脚本中可以看出JS获得页面元素后还进行了一定的格式化处理,在每个元素之间加了;,符号,这也是为了在后面代码中更加方便地解析。脚本的最后调用了finished()函数,即弹出包含robotium-finished的提示框。这一步完成了页面元素的获取,那么提示框中包含的内容在Android中怎么获取呢?

第二步:在Android中获取WebView中prompt提示框中的信息

        在Android的Webkit包中有个WebChromeClient类,这个类中的onJsPrompt方法就是用于处理WebView中的提示框的,当WebView中有JS提示框时,会回调该方法,String message参数将包含提示框中的信息,因此robotium写了个继承自WebChromeClient类的RobotiumWebClient类。覆写了onJsPrompt

onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result)

[java] view plaincopy技术分享技术分享

  1. @Override  

  2. public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult r) {  

  3.   

  4.     if(message != null && (message.contains(";,") || message.contains("robotium-finished"))){  

  5.                        //如果提示框中包含robotium-finished字符串,即表示那段JS注入脚本执行完毕了  

  6.         if(message.equals("robotium-finished")){  

  7.             webElementCreator.setFinished(true);  

  8.         }  

  9.         else{  

  10.             webElementCreator.createWebElementAndAddInList(message, view);//有人提示框中的内容,那么就可以对提示框中的内容进行处理了  

  11.         }  

  12.         r.confirm();  

  13.         return true;  

  14.     }  

  15.     else {  

  16.         if(originalWebChromeClient != null) {  

  17.             return originalWebChromeClient.onJsPrompt(view, url, message, defaultValue, r);   

  18.         }  

  19.         return true;  

  20.     }  

  21.   

  22. }  

      

     另外,原本的WebView默认是不允许执行JS的,因此需要先执行enableJavascriptAndSetRobotiumWebClient方法。将JavaScriptEnabled设置为true,将将WebChromeClient设置为robotiumWebClient

[java] view plaincopy技术分享技术分享

  1. public void enableJavascriptAndSetRobotiumWebClient(List<WebView> webViews, WebChromeClient originalWebChromeClient){  

  2.     this.originalWebChromeClient = originalWebChromeClient;  

  3.   

  4.     for(final WebView webView : webViews){  

  5.   

  6.         if(webView != null){   

  7.             inst.runOnMainSync(new Runnable() {  

  8.                 public void run() {  

  9.                     webView.getSettings().setJavaScriptEnabled(true);  

  10.                     webView.setWebChromeClient(robotiumWebClient);  

  11.   

  12.                 }  

  13.             });  

  14.         }  

  15.     }  

  16. }  

第三步:将提示框中的消息存入WebElement Java bean中

        获取到了prompt提示框中的消息后,接下来就是对这些已经过处理含特殊格式的消息进行解析处理了,依次得到WebElement的id、text、name等字段。

技术分享

[java] view plaincopy技术分享技术分享

  1. private WebElement createWebElementAndSetLocation(String information, WebView webView){  

  2.     String[] data = information.split(";,");            //将消息按;,符号分割,其中;,符号是在前面执行JS时加入的  

  3.     String[] elements = null;  

  4.     int x = 0;  

  5.     int y = 0;  

  6.     int width = 0;  

  7.     int height = 0;  

  8.     Hashtable<String, String> attributes = new Hashtable<String, String>();  

  9.     try{  

  10.         x = Math.round(Float.valueOf(data[5]));  

  11.         y = Math.round(Float.valueOf(data[6]));  

  12.         width = Math.round(Float.valueOf(data[7]));  

  13.         height = Math.round(Float.valueOf(data[8]));      

  14.         elements = data[9].split("\\#\\$");  

  15.     }catch(Exception ignored){}  

  16.   

  17.     if(elements != null) {  

  18.         for (int index = 0; index < elements.length; index++){  

  19.             String[] element = elements[index].split("::");  

  20.             if (element.length > 1) {  

  21.                 attributes.put(element[0], element[1]);  

  22.             } else {  

  23.                 attributes.put(element[0], element[0]);  

  24.             }  

  25.         }  

  26.     }  

  27.   

  28.     WebElement webElement = null;  

  29.   

  30.     try{  

  31.         webElement = new WebElement(data[0], data[1], data[2], data[3], data[4], attributes);//将id、text、name等字段存入  

  32.         setLocation(webElement, webView, x, y, width, height);  

  33.     }catch(Exception ignored) {}  

  34.   

  35.     return webElement;  

  36. }  

[java] view plaincopy技术分享技术分享

  1. /** 

  2.  * Sets the location of a {@code WebElement}  

  3.  *  

  4.  * @param webElement the {@code TextView} object to set location  

  5.  * @param webView the {@code WebView} the text is shown in 

  6.  * @param x the x location to set 

  7.  * @param y the y location to set 

  8.  * @param width the width to set 

  9.  * @param height the height to set 

  10.  */  

  11.   

  12. private void setLocation(WebElement webElement, WebView webView, int x, int y, int width, int height ){  

  13.     float scale = webView.getScale();  

  14.     int[] locationOfWebViewXY = new int[2];  

  15.     webView.getLocationOnScreen(locationOfWebViewXY);  

  16.   

  17.     int locationX = (int) (locationOfWebViewXY[0] + (x + (Math.floor(width / 2))) * scale);  

  18.     int locationY = (int) (locationOfWebViewXY[1] + (y + (Math.floor(height / 2))) * scale);  

  19.   

  20.     webElement.setLocationX(locationX);  

  21.     webElement.setLocationY(locationY);  

  22. }  

至此,WebElement对象中包含了id、text、name等字段,还包含了x、y坐标,知道了坐标后就可以像其它Android中的原生View一样根据坐标发送点击事件。


robotium原理之获取WebElement元素

标签:

原文地址:http://my.oschina.net/ghm7753/blog/475813

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!