无论是iOS还是Android,通常都会用到混合模式开发,这就要使用到WebView了,通过js和原生交互,可以实现很多功能。今天就来研究一下WebView

加载方式

加载一个网页:

webView.loadUrl("https://www.baidu.com/");

加载一个静态html

webView.loadUrl("file:///android_asset/test.html");

WebSettings

主要是针对WebView做一些设置,比如是否启用js等。

WebSettings webSettings = mWebView .getSettings();
//支持获取手势焦点,输入用户名、密码或其他
webview.requestFocusFromTouch();
setJavaScriptEnabled(true); //支持js
setPluginsEnabled(true); //支持插件
webSettings.setRenderPriority(RenderPriority.HIGH); //提高渲染的优先级
//设置自适应屏幕,两者合用
setUseWideViewPort(true); //将图片调整到适合webview的大小
setLoadWithOverviewMode(true); // 缩放至屏幕的大小
setSupportZoom(true); //支持缩放,默认为true。是下面那个的前提。
setBuiltInZoomControls(true); //设置内置的缩放控件。
//若上面是false,则该WebView不可缩放,这个不管设置什么都不能缩放。
setTextZoom(2);//设置文本的缩放倍数,默认为 100
setDisplayZoomControls(false); //隐藏原生的缩放控件
setLayoutAlgorithm(LayoutAlgorithm.SINGLE_COLUMN); //支持内容重新布局
supportMultipleWindows(); //多窗口
setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK); //关闭webview中缓存
setAllowFileAccess(true); //设置可以访问文件
setNeedInitialFocus(true); //当webview调用requestFocus时为webview设置节点
setJavaScriptCanOpenWindowsAutomatically(true); //支持通过JS打开新窗口
setLoadsImagesAutomatically(true); //支持自动加载图片
setDefaultTextEncodingName("utf-8");//设置编码格式
setStandardFontFamily("");//设置 WebView 的字体,默认字体为 "sans-serif"
setDefaultFontSize(20);//设置 WebView 字体的大小,默认大小为 16
setMinimumFontSize(12);//设置 WebView 支持的最小字体大小,默认为 8

WebViewClient

WebViewClient就是帮助WebView处理各种通知、请求事件的。

mWebView.setWebViewClient(new WebViewClient(){
//此方法表示是否覆盖重定向,即是否允许打开重定向,
//返回true表示不打开重定向,一般情况下,为了适配Android老版本,
//我们这里统一返回true,调用我们自己的webView来打开重定向。
//切记,不是所有请求都会走这个方法,只有重定向才会走
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
Log.d("aaa", "shouldOverrideUrlLoading1: "+request.getUrl().toString());
view.loadUrl(request.getUrl().toString());
return true;
}
//此方法同上
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
Log.d("aaa", "shouldOverrideUrlLoading2: "+url);
view.loadUrl(url);
return true;
}
//这个事件就是开始载入页面调用的,我们可以设定一个loading的页面,告诉用户程序在等待网络响应。
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
Log.d("aaa", "onPageStarted: "+url);
super.onPageStarted(view, url, favicon);
}
//在页面加载结束时调用。同样道理,我们可以关闭loading 条,切换程序动作。
@Override
public void onPageFinished(WebView view, String url) {
Log.d("aaa", "onPageFinished: "+url);
super.onPageFinished(view, url);
}
//加载错误信息
@Override
public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
Toast.makeText(MyWebViewActivity.this,error.toString(),Toast.LENGTH_SHORT).show();
Log.d("aaa", "onReceivedError: "+error.toString());
super.onReceivedError(view, request, error);
}
// 在加载页面资源时会调用,每一个资源(比如图片)的加载都会调用一次。
@Override
public void onLoadResource(WebView view, String url) {
Log.d("aaa", "onLoadResource: "+url);
}
//此方法表示是否禁用网页中的按键事件,比如键盘输入等
@Override
public boolean shouldOverrideKeyEvent(WebView view, KeyEvent event) {
return super.shouldOverrideKeyEvent(view,event);
}
//拦截替换网络请求数据 我们可以在这里返回我们自己的数据
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
return super.shouldInterceptRequest(view, request);
}
//同上
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
return super.shouldInterceptRequest(view, url);
}
//更新历史记录
@Override
public void doUpdateVisitedHistory(WebView view, String url, boolean isReload) {
super.doUpdateVisitedHistory(view, url, isReload);
}
//(应用程序重新请求网页数据)
@Override
public void onFormResubmission(WebView view, Message dontResend, Message resend) {
super.onFormResubmission(view, dontResend, resend);
}
//(获取返回信息授权请求)
@Override
public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host, String realm) {
super.onReceivedHttpAuthRequest(view, handler, host, realm);
}
//重写此方法可以让webview处理https请求。
@Override
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
super.onReceivedSslError(view, handler, error);
}
// (WebView发生改变时调用)
@Override
public void onScaleChanged(WebView view, float oldScale, float newScale) {
super.onScaleChanged(view, oldScale, newScale);
}
//(Key事件未被加载时调用)
@Override
public void onUnhandledKeyEvent(WebView view, KeyEvent event) {
super.onUnhandledKeyEvent(view, event);
}
});

WebChromeClient

WebChromeClient是辅助WebView处理js的各种事件。

mWebView.setWebChromeClient(new WebChromeClient(){
//当js调用alert()方法后,会调用此方法 返回true表示弹出
@Override
public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
return super.onJsAlert(view, url, message, result);
}
//处理prompt弹出框
@Override
public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
return super.onJsPrompt(view, url, message, defaultValue, result);
}
//处理confirm弹出框
@Override
public boolean onJsConfirm(WebView view, String url, String message, JsResult result) {
return super.onJsConfirm(view, url, message, result);
}
//获得网页的加载进度 0-100 这里可以更新进度条
@Override
public void onProgressChanged(WebView view, int newProgress) {
super.onProgressChanged(view, newProgress);
}
//获取网页中的title
@Override
public void onReceivedTitle(WebView view, String title) {
Log.d("aaa", "onReceivedTitle: "+title);
super.onReceivedTitle(view, title);
}
//获取网页的icon
@Override
public void onReceivedIcon(WebView view, Bitmap icon) {
super.onReceivedIcon(view, icon);
}
});

WebView的方法

前进、后退:

goBack()//后退
goForward()//前进
goBackOrForward(intsteps) //以当前的index为起始点前进或者后退到历史记录中指定的steps,如果steps为负数则为后退,正数则为前进
canGoForward()//是否可以前进
canGoBack() //是否可以后退

通常情况下,我们可以拦截系统的回退按钮,判断网页是否回退完,否者退出Activity

@Override
public void onBackPressed() {
if (mWebView.canGoBack()) {
mWebView.goBack();
}else {
finish();
}
}

WebView的状态:

onResume() //激活WebView为活跃状态,能正常执行网页的响应
onPause()//当页面被失去焦点被切换到后台不可见状态,需要执行onPause动过, onPause动作通知内核暂停所有的动作,比如DOM的解析、plugin的执行、JavaScript执行。
pauseTimers()//当应用程序被切换到后台我们使用了webview, 这个方法不仅仅针对当前的webview而是全局的全应用程序的webview,它会暂停所有webview的layout,parsing,javascripttimer。降低CPU功耗。
resumeTimers()//恢复pauseTimers时的动作。
destroy()//销毁,关闭了Activity时,音乐或视频,还在播放。就必须销毁。

注意:webview调用destory时,webview仍绑定在Activity上。这是由于自定义webview构建时传入了该Activitycontext对象,因此需要先从父容器中移除webview,然后再销毁webview

rootLayout.removeView(webView);
webView.destroy();

判断WebView是否已经滚动到页面底端或者顶端:

getScrollY() //方法返回的是当前可见区域的顶端距整个页面顶端的距离,也就是当前内容滚动的距离.
getHeight()或者getBottom() //方法都返回当前WebView这个容器的高度
getContentHeight() //返回的是整个html的高度,但并不等同于当前整个页面的高度,因为WebView有缩放功能,所以当前整个页面的高度实际上应该是原始html的高度再乘上缩放比例

获取当前WebView的真实的高度:

if (webView.getContentHeight() * webView.getScale() == (webView.getHeight() + webView.getScrollY())) {
//已经处于底端
}
if(webView.getScrollY() == 0){
//处于顶端
}

与js交互

首先,必须打开与js交互的开关:

webSettings.setJavaScriptEnabled(true);

原生调用js的方法:

@RequiresApi(api = Build.VERSION_CODES.KITKAT)
public void jsButtonClick(View v) {
mWebView.evaluateJavascript("javascript:alert('s')", new ValueCallback<String>() {
@Override
public void onReceiveValue(String value) {
Log.d("aaa", "onReceiveValue: "+value+"---thread:"+Thread.currentThread());
}
});
}

js调用原生方法,例如我们的html如下:

<html>
<head>
<script language="javascript">
function play(){
obj.play('abc');
}
</script>
</head>
<body bgcolor="black">
<a onClick="play()">
<img id="image" src="ic_launcher.png"/>
</a>
</body>
</html>

当点击图片的时候,会调用原生的play方法,并传递一个参数。

首先,创建一个类:

class JSObject {
@JavascriptInterface
public void play(String name) {
Log.d("aaa", "play: "+name);
}
}

记住,方法名一定要和js中的方法名一致,而且参数也一定要一致。并且需要在方法前加@JavascriptInterface注解,这样js才能调用到我们的原生方法。然后这样设定:

mWebView.addJavascriptInterface(new JSObject(),"obj");

这个obj就是我们在js中定义的对象。

总结

关于WebView的基本使用就这么多了,基本上能满足我们的日常开发。