Android中WebView与JS的交互
2016-07-22 16:58
411 查看
上家公司的主打产品是一个游戏社交类应用,里边有一套用户等级系统和一套付费系统。由于这个两套系统的界面不是固定的,而且支持的状态也根据用户的等级而有所不同,有时还需要根据节日或者当前推广的内容进行动态的调整。所以采用了webview加载页面的方式来实现。当然就免除不了会有Android原生方法与JS方法互相调用的情况。这里通过一个简单的例子阐述互调的实现方法,还有注意事项。
这里定义了三个供JS调用的方法,需要为每个方法添加@JavascriptInterface:因为安全问题,在Android4.2以上版本,JS只能访问带有 @JavascriptInterface注解的Java函数
该html文件给出了三种格式:
整形数据,可以直接获取到
字符串,也可以获取到
复杂数据:拼装成Json格式,再调用JS的方法转换成字符串后返回
1 4.2以上的系统需要增加@JavascriptInterface注解
2 JS调用的Android方法,内部的实现需要放在主线程进行
3 JS调用Java函数时,传递的参数格式有误也会导致调用不正常
实现
1 定义一个提供方法给JS调用的类
final class TaskInterface { private Context context; public TaskInterface(Context context) { this.context = context; } @JavascriptInterface public void showString(final String message) { handler.post(new Runnable() { @Override public void run() { AlertDialog.Builder builder = new AlertDialog.Builder( context); builder.setTitle(getString(R.string.app_name)); builder.setMessage(message); builder.setPositiveButton("确定", new OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); } }); builder.show(); } }); } @JavascriptInterface public void showNum(final int num) { handler.post(new Runnable() { @Override public void run() { AlertDialog.Builder builder = new AlertDialog.Builder( context); builder.setTitle(getString(R.string.app_name)); builder.setMessage("js传递给android的参数为:" + num); builder.setPositiveButton("确定", new OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); } }); builder.show(); } }); } @JavascriptInterface public void showJsonString(final String object) { handler.post(new Runnable() { @Override public void run() { AlertDialog.Builder builder = new AlertDialog.Builder( context); builder.setTitle(getString(R.string.app_name)); JSONObject jsonObject; try { jsonObject = new JSONObject(object); builder.setMessage("name的值为:" + jsonObject.getString("name") + "||||" + "age的值为:" + jsonObject.getString("age")); } catch (JSONException e) { e.printStackTrace(); } builder.setPositiveButton("确定", new OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); } }); builder.show(); } }); } }
这里定义了三个供JS调用的方法,需要为每个方法添加@JavascriptInterface:因为安全问题,在Android4.2以上版本,JS只能访问带有 @JavascriptInterface注解的Java函数
2 将该类的实例注入到WebView中
WebSettings webSettings = webView.getSettings(); // 需要与JS交互,必须先设置为true webSettings.setJavaScriptEnabled(true); // 将提供方法给JS调用的实例注入到WebView中 // Task:可以理解为JS使用该实例的一个标识 webView.addJavascriptInterface(new TaskInterface(this), "Task");
3 在JS调用Android提供的方法
// 有两种常用调用形式 javascript:Task.showString('传递简单字符串') window.Task.showNum(324343)
4 WebView调用JS的方法
// callJsMethod()为JS定义的方法 webView.loadUrl("javascript:callJsMethod()");
JS调用Android方法可传递的参数类型
<!DOCTYPE html> <html> <head> <title>Android与JS互调</title> </head> <body> <h1 align="center">Android与JS互调</h1> <script> function callJsMethod(){ document.getElementById("div").innerHTML+="<br\>这是android调用js方法动态添加的内容"; } </script> <p></p> <h3>Android调用JS动态添加的标签</h3> <p></p> <div onclick="window.Task.showNum(324343)"><u>js调用android方法:传递整形数据</u></div> <p></p> <div onclick="javascript:Task.showString('传递简单字符串')"><u>js调用android方法:传递简单字符串</u></div> <p></p> <div onclick="act.showObject()"><u>js调用android方法:传递json格式字符串</u></div> <p></p> <div onclick="window.Task.showString('js调用android方法的另一种形式:window.Task.showDialog')"><u>js调用android方法的另一种形式</u></div> <p></p> <p></p> <h3>Android调用JS动态添加的标签</h3> <div id="div"/> </body> <script> var act = { showObject:function(){ var params = { "name": "jacky", "age": 123456 }; params = JSON.stringify(params); javascript:Task.showJsonString(params); } }; </script> </html>
该html文件给出了三种格式:
整形数据,可以直接获取到
字符串,也可以获取到
复杂数据:拼装成Json格式,再调用JS的方法转换成字符串后返回
3 总结
调用的过程中,经常会遇到没有正确调用的情况。但由于又没有错误的提示,难免会给调试增加难度。这里给出几点遇到过的坑:1 4.2以上的系统需要增加@JavascriptInterface注解
2 JS调用的Android方法,内部的实现需要放在主线程进行
3 JS调用Java函数时,传递的参数格式有误也会导致调用不正常
4 官方文档
其实,官方对于一些常用的api都会有详细的说明或者解释,我们可以多查看这些说明,对于我们的开发有很大的帮助。这是给出addJavascriptInterface方法的官方说明。其实挺详细,对于一般的用法都有说明/** * Injects the supplied Java object into this WebView. The object is * injected into the JavaScript context of the main frame, using the * supplied name. This allows the Java object's methods to be * accessed from JavaScript. For applications targeted to API * level {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1} * and above, only public methods that are annotated with * {@link android.webkit.JavascriptInterface} can be accessed from JavaScript. * For applications targeted to API level {@link android.os.Build.VERSION_CODES#JELLY_BEAN} or below, * all public methods (including the inherited ones) can be accessed, see the * important security note below for implications. * <p> Note that injected objects will not * appear in JavaScript until the page is next (re)loaded. For example: * <pre> * class JsObject { * {@literal @}JavascriptInterface * public String toString() { return "injectedObject"; } * } * webView.addJavascriptInterface(new JsObject(), "injectedObject"); * webView.loadData("<!DOCTYPE html><title></title>", "text/html", null); * webView.loadUrl("javascript:alert(injectedObject.toString())");</pre> * <p> * <strong>IMPORTANT:</strong> * <ul> * <li> This method can be used to allow JavaScript to control the host * application. This is a powerful feature, but also presents a security * risk for apps targeting {@link android.os.Build.VERSION_CODES#JELLY_BEAN} or earlier. * Apps that target a version later than {@link android.os.Build.VERSION_CODES#JELLY_BEAN} * are still vulnerable if the app runs on a device running Android earlier than 4.2. * The most secure way to use this method is to target {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1} * and to ensure the method is called only when running on Android 4.2 or later. * With these older versions, JavaScript could use reflection to access an * injected object's public fields. Use of this method in a WebView * containing untrusted content could allow an attacker to manipulate the * host application in unintended ways, executing Java code with the * permissions of the host application. Use extreme care when using this * method in a WebView which could contain untrusted content.</li> * <li> JavaScript interacts with Java object on a private, background * thread of this WebView. Care is therefore required to maintain thread * safety. * </li> * <li> The Java object's fields are not accessible.</li> * <li> For applications targeted to API level {@link android.os.Build.VERSION_CODES#LOLLIPOP} * and above, methods of injected Java objects are enumerable from * JavaScript.</li> * </ul> * * @param object the Java object to inject into this WebView's JavaScript * context. Null values are ignored. * @param name the name used to expose the object in JavaScript */ public void addJavascriptInterface(Object object, String name) { checkThread(); mProvider.addJavascriptInterface(object, name); }
相关文章推荐
- android studio自定义toolbar
- android SDK开发 -- TitleBar封装(一)
- Retrofit2 源码分析
- Android自定义View 简单实现多图片选择控件
- android studio listview控件基础
- Android直播气泡效果
- android developer tiny share-20160722
- android developer tiny share-20160722
- Android 商品倒计时(DigitalClock实现倒计时 )
- Android中AlertDialog对话框禁止按 返回键、搜索键
- Android自定义View 简单实现多图片选择控件
- 通过ip连接android adb
- 2016年国内开源镜像站点汇总
- Android继承Mob短信验证详解
- Android自定义View自定义圆形Dialog
- Socket实现文件互传(二)
- Android view 详解(四) 自定义view
- 如何在Android Studio中创建assets文件夹
- [Android]仿支付宝自定义View密码框
- 从Mvc到Mvp