通过WebView在javascript里调用java 方法代码, 在java代码里执行javascript代码, 二者通过json进行数据交换

设置 WebView 小部件
// connect to our browser so we can manipulate itbrowser = (WebView) findViewById(R.id.calculator);// set a webview client to override the default functionalitybrowser.setWebViewClient(new wvClient());// get settings so we can config our WebView instanceWebSettings settings = browser.getSettings();// JavaScript?  Of course!settings.setJavaScriptEnabled(true);// clear cachebrowser.clearCache(true);// this is necessary for "alert()" to workbrowser.setWebChromeClient(new WebChromeClient());// add our custom functionality to the javascript environmentbrowser.addJavascriptInterface(new CalculatorHandler(), "calc");// uncomment this if you want to use the webview as an invisible calculator!//browser.setVisibility(View.INVISIBLE);// load a page to get things startedbrowser.loadUrl("file:///android_asset/index.html");// allows the control to receive focus// on some versions of Android the webview doesn't handle input focus properly// this seems to make things work with Android 2.1, but not 2.2// browser.requestFocusFromTouch();


将一个名为 browser 的 Activity 范围变量捆绑到了 WebView 控件。WebView 是一个相当复杂的类,可高度定制。例如,您需要设置几个类,以得到与 web 浏览器相关的预期函数。这是程序员必须投入一定精力来得到一些有用函数的地方之一。但是,此定制是没有限制的。对于此应用程序的目的来说,WebView 控件已经进行了最低限度的部署。

WebViewClient 提供用于捕获各种事件的钩子,这些事件包括页面加载开始和结束、表单重新提交、键盘截取以及程序员喜欢跟踪并操纵的很多其他事件。类似地,您需要 WebChromeClient 的一个实例,用于允许诸如非常有用的 alert() JavaScript 函数之类的函数。使用 WebSettings 来为控件启用 JavaScript。


连接 JavaScript 接口

下一步是启用 Activity 中的 Java 代码,以与 WebView 管理的 HTML 文件中的 JavaScript 代码交互。这是通过调用 addJavascriptInterface() 方法完成的,如 清单 4 所示。

该函数的参数是一个 Java 类的实例和一个名称空间标识符。例如,对于这个应用程序,您定义一个 calc 名称空间,并实现名为 CalculatorHandler 的类中的代码,如 清单 5 所示。

清单 5. CalculatorHandler 实现
// Javascript handlerfinal class CalculatorHandler{    private int iterations = 0;    // write to LogCat (Info)    public void Info(String str) {        iterations++;        Log.i("Calc",str);    }    // write to LogCat (Error)    public void Error(String str) {        iterations++;        Log.e("Calc",str);    }    // sample to retrieve a custom - written function with the details provided    // by the Android native application code    public String GetSomeFunction()    {        iterations++;        return "var q = 6;function dynamicFunc(v) { return v + q; }";    }    // Kill the app    public void EndApp() {        iterations++;        finish();    }    public void setAnswer(String a)    {        iterations++;        Log.i(tag,"Answer [" + a + "]");    }    public int getIterations()    {        return iterations;    }    public void SendHistory(String s)    {        Log.i("Calc","SendHistory" + s);        try {            JSONArray ja = new JSONArray(s);            for (int i=0;i<ja.length();i++) {                Log.i("Calc","History entry #" + (i+1) + " is [" + ja.getString(i)+ "]");            }        } catch (Exception ee) {            Log.e("Calc",ee.getMessage());        }    }}

在 JavaScript 环境中,通过 window.calc.methodname 语法访问 CalculatorHandler 的方法。例如,CalculatorHandler 实现一个名为 Info() 的方法,后者接受一个字符串参数并将之写到应用程序日志中。要从 JavaScript 环境访问此方法,可使用类似这样的语法:window.calc.Info("write this string to the application log!");。

基本了解了如何从 JavaScript 代码调用 Java 代码之后,我们再来看 清单 6 中的 index.html 文件,看各种方法是如何被调用的。

清单 6. WebView 控件中呈现(和执行)的 index.html
<html><head><meta name="viewport" content="width=device-width,initial-scale=0.25,    user-scalable=yes" /><title>Android to JavaScript with JSON</title></head><script language="JavaScript">var cmdHistory = new Array();function startup() {    try {        window.calc.Info("Starting up....");        cmdHistory[cmdHistory.length] = "startup";    } catch (ee) {    }}function PerformSimpleCalculation(formula) {    try {        cmdHistory[cmdHistory.length] = "PerformSimpleCalculation";        var answer = eval(String(formula));        document.getElementById('data').value = answer;        window.calc.setAnswer(answer);    }    catch (ee)     {        window.calc.Error(ee);    }}function PerformComplexCalculation(andmethod) {    try    {        /*         * argument to this function is a single object with 2 "members or properties"         * operation: this is a string naming what we want the function to do.         * array of arguments: this is an array of integers         *         */        //alert(andmethod.operation);        //alert(andmethod.arguments.length);        if (andmethod.operation == "addarray") {            cmdHistory[cmdHistory.length] = "PerformCompleCalculation-addarray";            var i;            var result = 0;            for (i=0;i<andmethod.arguments.length;i++) {                result += andmethod.arguments[i];            }            document.getElementById('data').value = result;            window.calc.setAnswer(result);        }        if (andmethod.operation == "multarray") {            cmdHistory[cmdHistory.length] = "PerformCompleCalculation-multarray";            var i;            var result = 1;            for (i=0;i<andmethod.arguments.length;i++) {                result *= andmethod.arguments[i];            }            document.getElementById('data').value = result;            window.calc.setAnswer(result);        }    }    catch (ee)    {        window.calc.Error(ee);    }}function dynamicfunction(){    try {        cmdHistory[cmdHistory.length] = "PerformCompleCalculation-dynamic";        eval(String(window.calc.GetSomeFunction()));        var result = dynamicFunc(parseInt(document.getElementById('data').value));        document.getElementById('data').value = result;    }catch (ee) {        alert(ee);    }}</script><body ><center><h3>Running in Web View :)</h3>this is some sample text here <br /><input type="text" id="data" value="starting value"><br /><button onclick="window.calc.Info(document.getElementById('data').value);">Log Info</button>&nbsp;&nbsp;<button onclick="window.calc.Error(document.getElementById('data').value);">Log Error</button><br /><button onclick="dynamicfunction();">Dynamic</button><button onclick="alert(String(window.calc.getIterations()));">How    Many Calls</button><button onclick="window.calc.SendHistory(JSON.stringify(cmdHistory));">    History</button><button onclick="if (window.confirm('End App?')) window.calc.EndApp();">Kill This App</button><br /></center></body></html>


仔细研究一下 清单 6 末尾的按钮处理程序。基本上,这些按钮处理程序都调用 window.calc 名称空间中的方法,这些方法在 AndroidJSON.java 中的 CalculatorHandler 类中实现。

清单 5 和 清单 6 协同工作,演示了 JavaScript 环境中初始化的和 Java 源文件中实现的代码交互。但是如何从 Activity 代码中初始化一些您想要在 WebView 中发生的动作呢?

现在应该更深入地来看 Java 代码了。

插入 JavaScript 代码

从将一个数学公式传递到 JavaScript 代码进行计算这样一个任务开始。JavaScript 最伟大(也最危险)的特性之一是 eval() 函数。eval() 函数允许字符串代码的运行时计算。在本例中,您从 EditText 控件接受一个字符串并传递到 JavaScript 环境进行计算。具体来说,我们调用 清单 6 中的 PerformSimpleCalculation() 函数。

清单 7 包含 AndroidJSON.java 中的代码,它负责处理按钮选择。

清单 7. 从 Java 调用 PerformSimpleCalculation() JavaScript 函数
  btnSimple.setOnClickListener(new OnClickListener()  {       public void onClick(View v) {         Log.i(tag,"onClick Simple");         // Perform action on click         try         {            String formulaText =  formula.getText().toString();            Log.i(tag,"Formula is [" + formulaText + "]" );            browser.loadUrl("javascript:PerformSimpleCalculation(" + formulaText + ");");         }         catch (Exception e)         {               Log.e(tag,"Error ..." + e.getMessage());         }       }  });


不管此方法有多少行,这里唯一要关注的是 browser.loadurl() 行,它传递一个格式字符串:javascript:<code to execute>。

此 JavaScript 代码被注入到 WebView 的当前页面并执行。这样,Java 代码就可以执行 WebView 中定义的 JavaScript 代码了。

在 Simple 例子中,传递了一个字符串。但是,当需要处理更复杂的结构时该怎么办呢?这就是 JSON 可派上用场的地方。清单 8 展示了 PerformComplexCalculation() 函数的调用,该函数参见 清单 6。

清单 8. 通过传递一个 JSON 对象调用更复杂的函数
btnComplex.setOnClickListener(new OnClickListener(){     public void onClick(View v) {         Log.i(tag,"onClick Complex");         // Perform action on click         try         {             String jsonText = "";             if (flipflop == 0)             {                 jsonText = "{ \"operation\" : \"addarray\",\"arguments\" : [1,2,3,4,5,6,7,8,9,10]}";                 flipflop = 1;             } else {                 jsonText = "{ \"operation\" : \"multarray\",\"arguments\" : [1,2,3,4,5,6,7,8,9,10]}";                 flipflop = 0;             }             Log.i(tag,"jsonText is [" + jsonText + "]" );             browser.loadUrl("javascript:PerformComplexCalculation(" + jsonText + ");");         }         catch (Exception e)         {             Log.e(tag,"Error ..." + e.getMessage());         }     }});


研究一下 清单 6 中的 JavaScript 函数 PerformComplexCalculation。注意,传递进来的参数不是字符串,而是您自己创建的一个对象。

* operation - 要处理的函数或过程的名称
* arguments - 这是一个整数数组

对象只包含两个属性,但是完全可以更复杂,以满足更高的需求。在本例中,PerformComplexCalculation() JavaScript 函数支持两种不同的操作:addarray 和 multarray。当这些操作在调用时完成其工作时,通过调用函数 window.calc.setAnswer,将结果传递回 Java 代码。这里,您看到了 Java 和 JavaScript 代码之间的双向数据流。

在本例中,您传递了一个 JSON 对象,但是得到的一条经验是,在处理从 Java 代码返回来的 Java 字符串时,它有助于将它们转换成 JavaScript 字符串。这可以像本例中一样通过将值传递给 String 函数来做到:eval(String(formula));。

JavaScript eval() 函数使用 JavaScript 字符串。无需转换的话,eval 函数基本上不做任何事情。

对于一个稍微复杂一点的例子,鼓励您好好看一下 Dynamic 按钮在 WebView 中被选中时的代码段。

要完成代码例子,来看一下将一个字符串数组从 JavaScript 环境传递到 Java 环境。

交换 JSON 对象

示例应用程序 (index.html) 中的 JavaScript 代码将本地函数调用记录到一个名为 cmdHistory 的页面级别数组中。每次调用函数时,您都将一个新条目添加到该数组中。例如,当 dynamicfunction() 被调用时,一个新的字符串被存储:cmdHistory[cmdHistory.length] = "PerformCompleCalculation-dynamic";。

关于此方法,没有什么特别的地方;它只是一个在页面级别收集使用数据的例子。也许该数据存储在 Android 应用程序的数据库中会有用。此数据如何回到 Java 代码呢?

要发送字符串对象数组,您调用 JSON.stringify 函数,将数组作为参数传递进来。根据需要,stringify 函数可以允许定制一个复杂对象的特定属性如何被格式化。关于这是如何完成的更多信息,可以参考 json.org 中的解释

更多相关文章

  1. Android单元测试 - 如何开始?
  2. android中listview的setAdapter()和getAdapter()
  3. Android简单调用相机Camera功能,实现打开照相功能
  4. Android(安卓)Toolchain与Bionic Libc
  5. Android(安卓)Studio NDK及so文件开发 以及常见错误
  6. android进行录音功能并保存播放
  7. Android(安卓)Binder简介
  8. Android(安卓)之 ServiceManager与服务管理
  9. 箭头函数的基础使用

随机推荐

  1. 一起Talk Android吧(第二百六十六回:Androi
  2. 【Android】最新主流新闻app功能实现。仿
  3. Android百度地图——在地图上标注已知GPS
  4. Android图像识别扫名片识别技术SDK
  5. android强制修改话机语言
  6. 【Android 电量优化】电量优化 ( 耗电量
  7. 从多方面理解Android体系结构
  8. Android OpenGLES2.0(八)——纹理贴图之显
  9. 【Android 设计】:样式_ 设备与显示 | 主
  10. Nexus One 吃下 Ice Cream Sandwich,操作