文章分两块,js调用andorid代码,android代码调用js
参考的博文http://blog.csdn.net/carson_ho/article/details/64904691
这也许是功能最强大的Android与Javascript交互开源库
前提 打开js交互 webview.getSetting().setJavaScriptEnable(true);
一:android调用js代码
说明:主要有两种方式,
方式1: 4.4系统以前
//需要另外开启线程
mWebView.post(new Runnable() {
// @Override
public void run() {
// 调用javascript的callJS()方法 ,,用于4.4以下,缺点:该方法会使页面再次刷新,且无法获取返回值
mWebView.loadUrl("javascript:callJS()");
}
});
方式2: 4.4系统以上
//4.4以上可用,优点:不会使页面再次刷新,且可以获取返回值
mWebView.evaluateJavascript("javascript:callJS()", new ValueCallback() {
@Override
public void onReceiveValue(String value) {
//此处为 js 返回的结果
}
});
综合使用:
if(Build.VERSION.SDK_INT<19){
mWebView.post(new Runnable() {
// @Override
public void run() {
// 调用javascript的callJS()方法 ,,用于4.4以下,缺点:该方法会使页面再次刷新,且无法获取返回值
mWebView.loadUrl("javascript:callJS()");
}
});
}else{
//4.4以上可用,优点:不会使页面再次刷新,且可以获取返回值
mWebView.evaluateJavascript("javascript:callJS()", new ValueCallback() {
@Override
public void onReceiveValue(String value) {
//此处为 js 返回的结果
}
});
}
二,js调用android代码
一: 通过addJavascriptInterface 接口
通过webView.addJavascriptInterface(new JsObject(), "injectedObject");接口
参考博文
4.2版本以前,我们一般是这么做的
//随便创建一个类
class JsObject {
//新建一个js要调用的方法
public String toString() { return "injectedObject"; }
}
//将该类的对象注入到js代码中
webView.addJavascriptInterface(new JsObject(), "injectedObject");
- [ 该方式有个致命漏洞,就是当js端得到我们注入的类对象的时候,可以通过类对象得到Java.lang.Runtime类,这样js就可以通过adb命令修改前端程序,比如文件修改等]
- 关于漏洞分析请看这篇文章
- js一般的攻击代码
function execute(cmdArgs)
{
// 步骤1:遍历 window 对象
// 目的是为了找到包含 getClass ()的对象
// 因为Android映射的JS对象也在window中,所以肯定会遍历到
for (var obj in window) {
if ("getClass" in window[obj]) {
// 步骤2:利用反射调用forName()得到Runtime类对象
alert(obj);
return window[obj].getClass().forName("java.lang.Runtime")
// 步骤3:以后,就可以调用静态方法来执行一些命令,比如访问文件的命令
getMethod("getRuntime",null).invoke(null,null).exec(cmdArgs);
// 从执行命令后返回的输入流中得到字符串,有很严重暴露隐私的危险。
// 如执行完访问文件的命令之后,就可以得到文件名的信息了。
}
}
}
4.2版本后:google修复了该漏动,虽有注入的类对象都必须添加@JavascriptInterface 注解,以代码只有该类的注解方法可以被js调用
webview.getSetting().setJavaScriptEnable(true);
class JsObject {
//js要调用的方法必须添加注解
@JavascriptInterface
public String toString() { return "injectedObject"; }
}
webView.addJavascriptInterface(new JsObject(), "injectedObject");
二.使用:
注意: 以下下代码必须要在loadurl前调用,也就是说需要先注入,再加载网页,否者无效
注入该对象,第二个参数则是js中要用的该对象的变量名
mWebView.addJavascriptInterface(new AndoridJs(), "test");//AndroidtoJS类对象映射到js的test对象
html代码
Carson
//点击按钮则调用callAndroid函数
二:通过 WebViewClient 的方法shouldOverrideUrlLoading ()回调拦截 url(无方式一存在的漏洞)
示例html
Carson_Ho
调用 :注意要和html上的沟通协议一样
// 复写WebViewClient类的shouldOverrideUrlLoading方法
mWebView.setWebViewClient(new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
// 步骤2:根据协议的参数,判断是否是所需要的url
// 一般根据scheme(协议格式) & authority(协议名)判断(前两个参数)
//假定传入进来的 url = "js://webview?arg1=111&arg2=222"(同时也是约定好的需要拦截的)
Uri uri = Uri.parse(url);
// 如果url的协议 = 预先约定的 js 协议
// 就解析往下解析参数
if ( uri.getScheme().equals("js")) {
// 如果 authority = 预先约定协议里的 webview,即代表都符合约定的协议
// 所以拦截url,下面JS开始调用Android需要的方法
if (uri.getAuthority().equals("webview")) {
// 步骤3:
// 执行JS所需要调用的逻辑
System.out.println("js调用了Android的方法");
// 可以在协议上带有参数并传递到Android上
HashMap params = new HashMap<>();
Set collection = uri.getQueryParameterNames();
}
return true;
}
return super.shouldOverrideUrlLoading(view, url);
}
}
);
++该方式缺点:JS获取Android方法的返回值复杂。若要返回给js值,就必须再通过andorid调用js的方法传递参数过去++
方式二 通过 WebChromeClient 的onJsAlert()、onJsConfirm()、onJsPrompt()方法回调拦截JS对话框alert()、confirm()、prompt() 消息
- 说明:
- 常用的拦截是:拦截 JS的输入框(即prompt()方法)
因为只有prompt()可以返回任意类型的值,操作最全面方便、更加灵活;而alert()对话框没有返回值;confirm()对话框只能返回两种状态(确定 / 取消)两个值
html示例:
Carson_Ho
使用:
// 设置允许JS弹窗
webSettings.setJavaScriptCanOpenWindowsAutomatically(true);
// 先加载JS代码
// 格式规定为:file:///android_asset/文件名.html
mWebView.loadUrl("file:///android_asset/javascript.html");
mWebView.setWebChromeClient(new WebChromeClient() {
// 拦截输入框(原理同方式2)
// 参数message:代表promt()的内容(不是url)
// 参数result:代表输入框的返回值
@Override
public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
// 根据协议的参数,判断是否是所需要的url(原理同方式2)
// 一般根据scheme(协议格式) & authority(协议名)判断(前两个参数)
//假定传入进来的 url = "js://webview?arg1=111&arg2=222"(同时也是约定好的需要拦截的)
Uri uri = Uri.parse(message);
// 如果url的协议 = 预先约定的 js 协议
// 就解析往下解析参数
if ( uri.getScheme().equals("js")) {
// 如果 authority = 预先约定协议里的 webview,即代表都符合约定的协议
// 所以拦截url,下面JS开始调用Android需要的方法
if (uri.getAuthority().equals("webview")) {
//
// 执行JS所需要调用的逻辑
System.out.println("js调用了Android的方法");
// 可以在协议上带有参数并传递到Android上
HashMap params = new HashMap<>();
Set collection = uri.getQueryParameterNames();
//参数result:代表消息框的返回值(输入值)
//注意记得把弹窗消费掉,否者下个页面可能会被卡住 result.confirm("js调用了Android的方法成功啦");
}
return true;
}
return super.onJsPrompt(view, url, message, defaultValue, result);
}
// 通过alert()和confirm()拦截的原理相同,此处不作过多讲述
// 拦截JS的警告框
@Override
public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
return super.onJsAlert(view, url, message, result);
}
// 拦截JS的确认框
@Override
public boolean onJsConfirm(WebView view, String url, String message, JsResult result) {
return super.onJsConfirm(view, url, message, result);
}
}
);
}