文章大纲
一、webview基本介绍
1.什么是webview
2.为什么要使用webview
3.webview基本操作
二、webview高级使用
1.WebView状态
2.资源加载
3.WebView加载优化
4.数据缓存
5.Android 和 JavaScript 交互
6.网页前进与后退
7.内存管理
8.Cookie操作
9.页面监听与拦截
10.定位设置
11.常见问题处理
三、参考文章
webview基本介绍
1.什么是webview
WebView是Android中的原生UI控件,主要用于在app应用中方便地访问远程网页或本地html资源。同时,WebView也在Android中充当Java代码和JS代码之间交互的桥梁。实际上,也可以将WebView看做一个功能最小化的浏览器。
2.为什么要使用webview
目前很多公司的 App 使用一个 WebView 作为网页加载, App 中的所有网页内容使用 HTML5 进行展示,这样只需要写一次 HTML5 代码,就可以在 Android 和 iOS 平台上运行,这就是所谓的跨平台 。随着 HTML5 的普及,很多 App 都会内嵌 WebView 来加载 HTML5 页面,即 原生和HTML5 共存,这就是当下最流行的「 混合开发 」。HTML5 最大的优势是迭代方便, 只需要修改服务端的 HTML5 页面,App 会同步更新,无论是做活动推广 App 还是及时修复 Bug 都带来的极大的便利。不过 HTML5 劣势也很明显,当网速不尽如人意时候,加载速度会很慢(不知道5G出现后结果会带来什么变革),也就是HTML5 加载受限于网络,没有原生控件流畅,用户体验相对较差, 所以目前完全使用 HTML5 开发 App 并没有成为主流。
3.webview基本操作
添加网络权限
在AndroidManifest.xml中添加以下内容
新建webview_simple.xml布局
在AndroidManifest.xml中注册WebViewActivity
WebViewActivity中代码如下:
import android.app.Activity;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.webkit.WebView;
public class WebViewActivity extends AppCompatActivity {
WebView webView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.webview_simple);
webView = (WebView) findViewById(R.id.webview);
//加载网页链接
webView.loadUrl("https://www.baidu.com");
}
}
主页面跳转代码如下:
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
public class MainActivity extends AppCompatActivity {
@BindView(R.id.button)
Button button;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
}
@OnClick({R.id.button, R.id.button2})
public void onViewClicked(View view) {
switch (view.getId()) {
//简单webview加载
case R.id.button:
startActivity(new Intent(MainActivity.this, WebViewActivity.class));
break;
}
}
}
运行截图如下所示:
网页弹窗
//message:alert弹出窗口中的提示信息(提示或警告信息对话框,仅一个确认按钮)
//result:向网页中的Javascript代码反馈本次操作结果(result.confirm代表点击了确定按钮,result.cancel代表点击了取消按钮)
public boolean onJsAlert(WebView view, String url, String message,JsResult result)
///message:confirm弹出窗口中的提示信息(确认对话框,有确认、取消两个按钮)
//result:向网页中的Javascript代码反馈本次操作结果(result.confirm代表点击了确定按钮,result.cancel代表点击了取消按钮)
public boolean onJsConfirm(WebView view, String url, String message,JsResult result)
//message:prompt弹出窗口中的提示信息(输入信息对话框,有一个输入框,还有确认、取消两个按钮)
//defaultValue:输入框中的默认信息
//result:向网页中的Javascript代码反馈本次操作结果(result.confirm代表点击了确定按钮,result.cancel代表点击了取消按钮)
public boolean onJsPrompt(WebView view, String url, String message,String defaultValue, JsPromptResult result)
下面给出一个简单的处理方案,可以作为参考:
@Override
public boolean onJsAlert(WebView view, String url, String message, final JsResult result) {
new AlertDialog.Builder(MainActivity.this)
.setTitle("JsAlert")
.setMessage(message)
.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
result.confirm();
}
})
.setCancelable(false)
.show();
return true;
}
@Override
public boolean onJsConfirm(WebView view, String url, String message, final JsResult result) {
new AlertDialog.Builder(MainActivity.this)
.setTitle("JsConfirm")
.setMessage(message)
.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
result.confirm();
}
})
.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
result.cancel();
}
})
.setCancelable(false)
.show();
return true;
}
@Override
public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, final JsPromptResult result) {
final EditText editText=new EditText(MainActivity.this);
editText.setText("默认数据");//设置默认数据
new AlertDialog.Builder(MainActivity.this)
.setTitle("JsPromt")
.setView(editText)//为弹出窗口设置输入框
.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
result.confirm(editText.getText().toString());//向Javascript传递输入值
}
})
.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
result.cancel();
}
})
.setCancelable(false)
.show();
return true;
}
二、webview高级使用
1.WebView状态
//激活WebView为活跃状态,能正常执行网页的响应
webView.onResume() ;
//当页面被失去焦点被切换到后台不可见状态,需要执行onPause
//通过onPause动作通知内核暂停所有的动作,比如DOM的解析、plugin的执行、JavaScript执行。
webView.onPause();
//当应用程序(存在webview)被切换到后台时,这个方法不仅仅针对当前的webview而是全局的全应用程序的webview
//它会暂停所有webview的layout,parsing,javascripttimer。降低CPU功耗。
webView.pauseTimers()
//恢复pauseTimers状态
webView.resumeTimers();
//销毁Webview
//在关闭了Activity时,如果Webview的音乐或视频,还在播放。就必须销毁Webview
//但是注意:webview调用destory时,webview仍绑定在Activity上
//这是由于自定义webview构建时传入了该Activity的context对象
//因此需要先从父容器中移除webview,然后再销毁webview:
rootLayout.removeView(webView);
webView.destroy();
2.资源加载
WebView可以加载多种资源,包括本地资源和远程资源,同时也有多种用于加载资源的方法。
加载assets中的资源
新建assets文件夹,再新建.html文件
在Activity中添加以下代码:
webView.loadUrl("file:///android_asset/test.html");//加载本地assets文件夹下的资源
加载res中的资源
webView.loadUrl(``"[file:///android_res/mipmap/ic_launcher.png](file:///android_res/mipmap/ic_launcher.png)"``);//加载本地res文件夹下的图片
webView.loadUrl(``"[file:///android_res/raw/ic_launcher.png](file:///android_res/raw/ic_launcher.png)"``);//加载本地res文件夹下raw文件夹下的图片
webView.loadUrl(``"[file:///android_res/raw/test.html](file:///android_res/raw/test.html)"``);//加载本地res文件夹下raw文件夹下的html文件
加载sdcard中的资源
webView.loadUrl(``"file:/sdcard/test.html");//加载本地sdcard下的资源
webView.loadUrl(``"[file:///sdcard/test.html](file:///sdcard/test.html)");//加载本地sdcard下的资源
webView.loadUrl(``"[content://com.android.htmlfileprovider/sdcard/test.html
请求远程网页方式
loadData(以字符串形式加载html片段)
//data:html片段
//mimeType:数据类型,如"text/html"
//encoding:数据编码,有两种可选值("base64"和其他任何值),分别代表base64编码和URL编码
public void loadData(String data, String mimeType, String encoding)
loadUrlWithBaseURL(以字符串形式加载html片段)
//baseUrl:基础url,传入null相当于传入了"about:blank"
//data:html片段
//mimeType:数据类型,如"text/html"
//encoding:数据编码,有两种可选值("base64"和其他任何值),分别代表base64编码和URL编码
//historyUrl:历史url
public void loadDataWithBaseURL(String baseUrl, String data,String mimeType, String encoding, String historyUrl)
postUrl(以post请求的形式访问url)
//postData:本次post请求携带的数据,必须是application/x-www-form-urlencoded编码
//如果传入的url不是一个远程网页地址,那么最终将通过loadUrl方法加载这个url,同时postData参数会被忽略。
public void postUrl(String url, byte[] postData)
3.WebView加载优化
设置页面自适应屏幕
webSettings.setUseWideViewPort(true);
webSettings.setLoadWithOverviewMode(true);
缩放功能
webSettings.setSupportZoom(true);//启用缩放功能
webSettings.setBuiltInZoomControls(true);//使用WebView内置的缩放功能
webSettings.setDisplayZoomControls(false);//隐藏屏幕中的虚拟缩放按钮
温馨提示:setDisplayZoomControls(true)在某些系统版本中可能会导致应用出现意外崩溃。
若加载的 html 里有JS 在执行动画等操作,会造成资源浪费(CPU、电量)
在 onStop 和 onResume 里分别把 setJavaScriptEnabled() 给设置成 false 和 true 即可
页面加载过程优化
处理各种通知 & 请求事件
//步骤1. 定义Webview组件
Webview webview = (WebView) findViewById(R.id.webView1);
//步骤2. 选择加载方式
//方式1. 加载一个网页:
webView.loadUrl("http://www.google.com/");
//步骤3. 复写shouldOverrideUrlLoading()方法,使得打开网页时不调用系统浏览器, 而是在本WebView中显示
webView.setWebViewClient(new WebViewClient(){
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;
}
});
onPageStarted()
作用:开始载入页面调用的,我们可以设定一个loading的页面,告诉用户程序在等待网络响应。
webView.setWebViewClient(new WebViewClient(){
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
//设定加载开始的操作
}
});
onPageFinished()
作用:在页面加载结束时调用。我们可以关闭loading 条,切换程序动作。
webView.setWebViewClient(new WebViewClient(){
@Override
public void onPageFinished(WebView view, String url) {
//设定加载结束的操作
}
});
onLoadResource()
作用:在加载页面资源时会调用,每一个资源(比如图片)的加载都会调用一次。
webView.setWebViewClient(new WebViewClient(){
@Override
public boolean onLoadResource(WebView view, String url) {
//设定加载资源的操作
}});
onReceivedError()
作用:加载页面的服务器出现错误时(如404)调用。App里面使用webview控件的时候遇到了诸如404这类的错误的时候,若也显示浏览器里面的那种错误提示页面就显得很丑陋了,那么这个时候我们的app就需要加载一个本地的错误提示页面,即webview如何加载一个本地的页面
//步骤1:写一个html文件(error_handle.html),用于出错时展示给用户看的提示页面
//步骤2:将该html文件放置到代码根目录的assets文件夹下
//步骤3:复写WebViewClient的onRecievedError方法
//该方法传回了错误码,根据错误类型可以进行不同的错误分类处理
webView.setWebViewClient(new WebViewClient(){
@Override
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl){
switch(errorCode)
{
case HttpStatus.SC_NOT_FOUND:
view.loadUrl("file:///android_assets/error_handle.html");
break;
} }
});
onReceivedSslError()
作用:处理https请求,webView默认是不处理https请求的,页面显示空白,需要进行如下设置:
webView.setWebViewClient(new WebViewClient() {
@Override
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
handler.proceed(); //表示等待证书响应
// handler.cancel(); //表示挂起连接,为默认方式
// handler.handleMessage(null); //可做其他处理
}
});
4.数据缓存
当加载 html 页面时,WebView会在/data/data/包名目录下生成 database 与 cache 两个文件夹
请求的 URL记录保存在 WebViewCache.db,而 URL的内容是保存在 WebViewCache 文件夹下,设置是否启动缓存方法如下:
WebView.getSettings().setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
缓存模式如下:
// LOAD_CACHE_ONLY: 不使用网络,只读取本地缓存数据
// LOAD_DEFAULT: (默认)根据cache-control决定是否从网络上取数据。
// LOAD_NO_CACHE: 不使用缓存,只从网络获取数据.
// LOAD_CACHE_ELSE_NETWORK,只要本地有,无论是否过期,或者no-cache,都使用缓存中的数据。
//WebView.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);不使用缓存
结合使用(离线加载)
if (NetStatusUtil.isConnected(getApplicationContext())) {
webSettings.setCacheMode(WebSettings.LOAD_DEFAULT);//根据cache-control决定是否从网络上取数据。
} else {
webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);//没网,则从本地获取,即离线加载
}
webSettings.setDomStorageEnabled(true); // 开启 DOM storage API 功能
webSettings.setDatabaseEnabled(true); //开启 database storage API 功能
webSettings.setAppCacheEnabled(true);//开启 Application Caches 功能
String cacheDirPath = getFilesDir().getAbsolutePath() + APP_CACAHE_DIRNAME;
webSettings.setAppCachePath(cacheDirPath); //设置 Application Caches 缓存目录
//注意: 每个 Application 只调用一次 WebSettings.setAppCachePath(),WebSettings.setAppCacheMaxSize()
清理缓存
//清除网页访问留下的缓存
//由于内核缓存是全局的因此这个方法不仅仅针对webview而是针对整个应用程序.
webView.clearCache(true);
//清除当前webview访问的历史记录
//只会webview访问历史记录里的所有记录除了当前访问记录
webView.clearHistory();
//这个api仅仅清除自动完成填充的表单数据,并不会清除WebView存储到本地的数据
webView.clearFormData();
另外一种方式:
//删除缓存文件夹
File file = CacheManager.getCacheFileBaseDir();
if (file != null && file.exists() && file.isDirectory()) {
for (File item : file.listFiles()) {
item.delete();
}
file.delete();
}
//删除缓存数据库
context.deleteDatabase("webview.db");
context.deleteDatabase("webviewCache.db");
5.Android 和 JavaScript 交互
安卓代码
WebSettings settings = mWebView.getSettings();
settings.setJavaScriptEnabled(true);//开启JavaScript
mWebView.loadUrl("file:///android_asset/keithxiaoy.html");//加载本地网页
mWebView.setWebChromeClient(new WebChromeClient());//此行代码可以保证JavaScript的Alert弹窗正常弹出
//核心方法, 用于处理JavaScript被执行后的回调
mWebView.addJavascriptInterface(new JsCallback() {
@JavascriptInterface//注意:此处一定要加该注解,否则在4.1+系统上运行失败
@Override
public void onJsCallback() {
System.out.println("JavaScript调用Android啦");
}
}, "keithxiaoy");//参1是回调接口的实现;参2是JavaScript回调对象的名称
//定义回调接口
public interface JsCallback {
public void onJsCallback();
}
Android 调用 JavaScript
//直接使用webview加载js就可以了
mWebView.loadUrl("javascript:wave()");
html代码如下
![](android_normal.png)
Click me!