WebView 常用的类
- WebView
- WebSettings
- WebViewClient
- WebChromeClient
- addJavascriptInterface
必要权限
一、WebView
(1)创建WebView
WebView webview = new WebView(this);
(2)加载url
- 加载网页 url地址
webView.loadUrl("http://www.jianshu.com/")
- 加载本地asset目录下的网页
注意:将index.html 放在asset目录下
webView.loadUrl("file:///android_asset/html/index.html"); //加载本地assert目录下网页
- 加载Sdcard上的html
(3) 返回和后退
webview是否可以返回到上一页面 webView.canGoBack()
webview返回到上一页面 webView.goBack();
webview是否可以前进 webView.canGoForward()
webview前进 webView.goForward();
二、WebSettings Webview设置类
设置WebView的一些属性、状态等,例如允许使用javascript,允许使用缓存,允许使用内置的缩放组件,设置支持IS等
//声明WebSettings子类
WebSettings webSettings = webView.getSettings();
//如果访问的页面中要与Javascript交互,则webview必须设置支持Javascript
webSettings.setJavaScriptEnabled(true);
// 若加载的 html 里有JS 在执行动画等操作,会造成资源浪费(CPU、电量)
// 在 onStop 和 onResume 里分别把 setJavaScriptEnabled() 给设置成 false 和 true 即可
//支持插件
webSettings.setPluginsEnabled(true);
//设置自适应屏幕,两者合用
webSettings.setUseWideViewPort(true); //将图片调整到适合webview的大小
webSettings.setLoadWithOverviewMode(true); // 缩放至屏幕的大小
//缩放操作
webSettings.setSupportZoom(true); //支持缩放,默认为true。是下面那个的前提。
webSettings.setBuiltInZoomControls(true); //设置内置的缩放控件。若为false,则该WebView不可缩放
webSettings.setDisplayZoomControls(false); //隐藏原生的缩放控件
//其他细节操作
webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK); //关闭webview中缓存
webSettings.setAllowFileAccess(true); //设置可以访问文件
webSettings.setJavaScriptCanOpenWindowsAutomatically(true); //支持通过JS打开新窗口
webSettings.setLoadsImagesAutomatically(true); //支持自动加载图片
webSettings.setDefaultTextEncodingName("utf-8");//设置编码格式
三、WebViewClient : 主要负责请求事件和各种通知(例如开始加载、加载完毕之后的动作、加载错误、对加载url链接的拦截)
webView.setWebViewClient(new WebViewClient() {
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
//页面开始加载时
super.onPageStarted(view, url, favicon);
}
@Override
public void onPageFinished(WebView view, String url) {
//页面加载结束时
super.onPageFinished(view, url);
}
@Override
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
super.onReceivedError(view, errorCode, description, failingUrl);
// 这里进行无网络或错误处理,具体可以根据errorCode的值进行判断,
}
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
/**
* 网页跳转:
* 1.在当前的webview跳转到新连接
* view.loadUrl(url);
* 2.调用系统浏览器跳转到新网页
* Intent i = new Intent(Intent.ACTION_VIEW);
* i.setData(Uri.parse(url));
* startActivity(i);
*/
return true;
}
});
四、WebChromeClient
辅助处理 javaScript的各种对话框、网站标题、网站图标、加载进度等。
webView.setWebChromeClient(new WebChromeClient() {
@Override
public void onProgressChanged(WebView view, int newProgress) {
// 获得网页的加载进度
super.onProgressChanged(view, newProgress);
}
@Override
public void onReceivedTitle(WebView view, String title) {
// 获取网页的title,客户端可以在这里动态修改页面的title
// 另外,当加载错误时title为“找不到该网页”
super.onReceivedTitle(view, title);
}
@Override
public final boolean onJsPrompt(WebView view, String url, String message,
String defaultValue, JsPromptResult result) {
if (view instanceof WebViewSafe) {
if (handleJsInterface(view, url, message, defaultValue, result)) {
return true;
}
}
return super.onJsPrompt(view, url, message, defaultValue, result);
}
});
五、与JS交互-addJavascriptInterface
mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.addJavascriptInterface(new JSInterface(), "jsInterface");
JSInterface对象:
public class JSInterface {
@JavascriptInterface
public void methodA() { }
@JavascriptInterface
public void methodB(String webMessage) { }
}
六、javaScript 与 Android 代码交互
1. Android 调用javascrpit代码
// 文本名:javascript
Carson_Ho
// JS代码
- webView.loadUrl();
loadUrl()方法 执行javaScript 会重新加载页面,效率低
mWebView.loadUrl("javascript:callJS()");
- 通过 wevView的evaluateJavascript()
evaluateJavascript()仅支持4.4以上的Android版本,无法向下兼容。但是onReceiveValue回调中,可以直接返回javaScript的返回值。使用方便,效率高。
// 只需要将第一种方法的loadUrl()换成下面该方法即可
mWebView.evaluateJavascript("javascript:callJS()", new ValueCallback() {
@Override
public void onReceiveValue(String value) {
//此处为 js 返回的结果
}
});
}
JS 调用Android代码
- 通过shouldOverrideUrlLoading回调 拦截webView的 url,调用Android代码。
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);
}
}
);
}
}
- 通过WebChromeClient 的onJsAlert()、onJsConfirm()、onJsPrompt()方法回调 拦截 JS对话框alert()、confirm()、prompt() 消息,调用Android代码。
Carson_Ho
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);
}
}
);
}
}
- 通过JavaScriptInterface,调用Android 代码。
Carson
//点击按钮则调用callAndroid函数
// 继承自Object类
public class AndroidtoJs extends Object {
// 定义JS需要调用的方法
// 被JS调用的方法必须加入@JavascriptInterface注解
@JavascriptInterface
public void hello(String msg) {
System.out.println("JS调用了Android的hello方法");
}
}
// 设置与Js交互的权限
webSettings.setJavaScriptEnabled(true);
// 通过addJavascriptInterface()将Java对象映射到JS对象
//参数1:Java对象名
//参数2:Javascript对象名
mWebView.addJavascriptInterface(new AndroidtoJs(), "test");//AndroidtoJS类对象映射到js的test对象
// 加载JS代码
// 格式规定为:file:///android_asset/文件名.html
mWebView.loadUrl("file:///android_asset/javascript.html");
七、 WebView 漏洞
webViewde 的任意代码执行漏洞,主要有三个原因
WebView 中 addJavascriptInterface() 接口。
解决 办法:
(1)Android 4.2版本之后
Google 在Android 4.2 版本中规定对被调用的函数以 @JavascriptInterface进行注解从而避免漏洞攻击
(2)Android 4.2版本之前
在Android 4.2版本之前采用拦截prompt()进行漏洞修复。searchBoxJavaBridge_接口引起远程代码执行漏洞
解决方法:删除searchBoxJavaBridge_接口
// 通过调用该方法删除接口
super.removeJavascriptInterface("searchBoxJavaBridge_");`
- accessibility和 accessibilityTraversal接口引起远程代码执行漏洞
删除接口
super.removeJavascriptInterface("accessibility");
super.removeJavascriptInterface("accessibilityTraversal");
参考链接:
WebView 常规用法:
https://www.jianshu.com/p/3c94ae673e2a
JS与Android交互
https://www.jianshu.com/p/345f4d8a5cfa
WebView漏洞分析:
https://www.jianshu.com/p/3a345d27cd42
如何点击h5中的图片 触发 Android原生的图片查看器:
https://www.jianshu.com/p/7167ee44cfcd