Android WebView
一、简介
WebView在Android平台上是一个特殊的View, 基于webkit引擎、展现web页面的控件,这个类可以被用来在你的app中仅仅显示一张在线的网页,还可以用来开发浏览器。WebView内部实现是采用渲染引擎来展示view的内容,提供网页前进后退,网页放大,缩小,搜索。Android的Webview在低版本和高版本采用了不同的webkit版本内核,4.4后直接使用了Chrome内核。
现在很多APP都内置了Web网页,比如说很多电商平台,淘宝、京东、聚划算等等。WebView比较灵活,不需要升级客户端,只需要修改网页代码即可。一些经常变化的页面可以用WebView这种方式去加载网页。例如中秋节跟国庆节打开的页面不一样,如果是用WebView显示的话,只修改修改html页面就行,而不需要升级客户端。
二、基本使用
1、添加网络权限
<uses-permission android:name="android.permission.INTERNET"/>
2、添加布局
<WebView
android:id="@+id/wv_webview"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
3、基本代码运用
webView = (WebView) findViewById(R.id.wv_webview);
// webView.loadUrl("file:///android_asset/test.html");//加载asset文件夹下html
webView.loadUrl("http://139.196.35.30:8080/OkHttpTest/apppackage/test.html");//加载url
webView.addJavascriptInterface(this,"android");//添加js监听 这样html就能调用客户端
webView.setWebChromeClient(webChromeClient);//辅助WebView处理Javascript的对话框,网站图标,网站title,加载进度条webView.setWebViewClient(webViewClient); //帮助WebView处理各种通知、请求事件
WebSettings webSettings=webView.getSettings();//对WebView进行配置和管理
webSettings.setJavaScriptEnabled(true);//允许使用js
LOAD_CACHE_ONLY: 不使用网络,只读取本地缓存数据
LOAD_DEFAULT: (默认)根据cache-control决定是否从网络上取数据。
LOAD_NO_CACHE: 不使用缓存,只从网络获取数据.
LOAD_CACHE_ELSE_NETWORK,只要本地有,无论是否过期,或者no-cache,都使用缓存中的数据。
webSettings.setCacheMode(WebSettings.LOAD_NO_CACHE);//不使用缓存,只从网络获取数据.
//支持屏幕缩放
webSettings.setSupportZoom(true);
webSettings.setBuiltInZoomControls(true);
三、常用方法
1、WebView常用方法
wvWebview.loadUrl(String url);// 加载网络链接 url
wvWebview.canGoBack();// 判断 WebView 当前是否可以返回上一页
wvWebview.goBack();// 回退到上一页
wvWebview.onResume();// 在调用onPause()后,可以调用该方法来恢复WebView 的运行
wvWebview.resumeTimers();// 恢复pauseTimers时的所有操作
wvWebview.onPause();// 类似 Activity 生命周期,页面进入后台不可见状态
wvWebview.pauseTimers();// 该方法面向全局整个应用程序的webview,它会暂停所有webview的layout,parsing,JavaScript Timer。当程序进入后台时,该方法的调用可以降低CPU功耗。
wvWebview.destroy();// 销毁 WebView
wvWebview.clearHistory();// 清空历史
wvWebview.clearCache(true);// 包括硬盘
wvWebview.reload();// 重新加载当前请求
wvWebview.removeAllViews();// 清除子view。
wvWebview.clearSslPreferences();// 清除ssl信息。
wvWebview.clearMatches();// 清除网页查找的高亮匹配字符。
wvWebview.removeJavascriptInterface(String interfaceName);// 删除interfaceName对应的注入对象
wvWebview.addJavascriptInterface(Object object,String interfaceName);//注入 java 对象。
wvWebview.setVerticalScrollBarEnabled(true);// 设置垂直方向滚动条。
wvWebview.setHorizontalScrollBarEnabled(true);// 设置横向滚动条。
wvWebview.loadUrl(String url, Map additionalHttpHeaders);// 加载制定url并携带http header数据。。
wvWebview.stopLoading();// 停止 WebView 当前加载。
wvWebview.freeMemory();// 释放内存,不过貌似不好用。
wvWebview.clearFormData();// 清除自动完成填充的表单数据。需要注意的是,该方法仅仅清除当前表单域自动完成填充的表单数据,并不会清除WebView存储到本地的数据。
2、WebSettings(对WebView进行配置和管理) 常用方法
finalString filesDir = getContext().getFilesDir().getPath();
finalString databaseDir = filesDir.substring(0, filesDir.lastIndexOf("/")) + DATABASES_SUB_FOLDER;
WebSettings webSettings = wvWebview.getSettings();
if(webSettings ==null)return;
webSettings.setJavaScriptEnabled(true);// 支持 Js 使用
webSettings.setDomStorageEnabled(true);// 开启DOM缓存
webSettings.setDatabaseEnabled(true);// 开启数据库缓存
webSettings.setLoadsImagesAutomatically(true);// 支持自动加载图片
webSettings.setCacheMode(WebSettings.LOAD_DEFAULT);// 设置 WebView 的缓存模式
webSettings.setAppCacheEnabled(true);// 支持启用缓存模式
// Android 私有缓存存储,如果你不调用setAppCachePath方法,WebView将不会产生这个目录
webSettings.setAppCachePath(getCacheDir().getAbsolutePath());
if(Build.VERSION.SDK_INT <19) {// 数据库路径
webSettings.setDatabasePath(databaseDir);
}
webSettings.setSupportZoom(true);// 支持缩放
webSettings.setUserAgentString("");// 设置 UserAgent 属性
webSettings.setAllowFileAccess(true);// 允许加载本地 html 文件/false
// 允许通过 file url 加载的 Javascript 读取其他的本地文件,Android 4.1 之前默认是true,在 Android 4.1 及以后默认是false,也就是禁止
webSettings.setAllowFileAccessFromFileURLs(false);
// 允许通过 file url 加载的 Javascript 可以访问其他的源,包括其他的文件和 http,https 等其他的源,
// Android 4.1 之前默认是true,在 Android 4.1 及以后默认是false,也就是禁止
// 如果此设置是允许,则 setAllowFileAccessFromFileURLs 不起做用
webSettings.setAllowUniversalAccessFromFileURLs(false);
webSettings.setDefaultTextEncodingName("utf-8");//设置编码格式
3、WebChromeClient(辅助WebView处理Javascript的对话框,网站图标,网站title,加载进度条)常用方法
wvWebview.setWebChromeClient(newMyWebChromeClient());
publicclassMyWebChromeClientextendsWebChromeClient{
/**输出 Web 端日志 */
@Override
publicbooleanonConsoleMessage(ConsoleMessage consoleMessage){
returnsuper.onConsoleMessage(consoleMessage);
}
/** * 当前 WebView 加载网页进度 */
@Override
publicvoidonProgressChanged(WebView view,intnewProgress){
super.onProgressChanged(view, newProgress);
}
/*** Js 中调用 alert() 函数,产生的对话框*/
@Override
publicbooleanonJsAlert(WebView view, String url, String message, JsResult result){
returnsuper.onJsAlert(view, url, message, result);
}
/** * 处理 Js 中的 Confirm 对话框*/
@Override
publicbooleanonJsConfirm(WebView view, String url, String message, JsResult result){
returnsuper.onJsConfirm(view, url, message, result);
}
/** * 处理 JS 中的 Prompt对话框 */
@Override
publicbooleanonJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result){
returnsuper.onJsPrompt(view, url, message, defaultValue, result);
}
/*** 接收web页面的icon*/
@Override
publicvoidonReceivedIcon(WebView view, Bitmap icon){
super.onReceivedIcon(view, icon);
}
/** * 接收web页面的 Title */
@Override
publicvoidonReceivedTitle(WebView view, String title){
super.onReceivedTitle(view, title);
}
}
4、WebViewClient(帮助WebView处理各种通知、请求事件)常用方法
wvWebview.setWebViewClient(newMyWebViewClient());
publicclassMyWebViewClientextendsWebViewClient{
/*** 当WebView得页面Scale值发生改变时回调 */
@Override
publicvoidonScaleChanged(WebView view,floatoldScale,floatnewScale){
super.onScaleChanged(view, oldScale, newScale);
}
/** * 是否在 WebView 内加载页面 */
@Override
publicbooleanshouldOverrideUrlLoading(WebView view, String url){
view.loadUrl(url);
returnsuper.shouldOverrideUrlLoading(view, url);
}
/** * WebView 开始加载页面时回调,一次Frame加载对应一次回调 */
@Override
publicvoidonPageStarted(WebView view, String url, Bitmap favicon){
super.onPageStarted(view, url, favicon);
}
/** * WebView 完成加载页面时回调,一次Frame加载对应一次回调 */
@Override
publicvoidonPageFinished(WebView view, String url){
super.onPageFinished(view, url);
}
/*** WebView 加载页面资源时会回调,每一个资源产生的一次网络加载,除非本地有当前 url 对应有缓存,否则就会加载。 */
@Override
publicvoidonLoadResource(WebView view, String url){
super.onLoadResource(view, url);
}
/** * WebView 可以拦截某一次的 request 来返回我们自己加载的数据,这个方法在后面缓存会有很大作用。*/
@Override
publicWebResourceResponseshouldInterceptRequest(WebView view, WebResourceRequest request){
returnsuper.shouldInterceptRequest(view, request);
}
/** * WebView 访问 url 出错 */
@Override
publicvoidonReceivedError(WebView view, WebResourceRequest request, WebResourceError error){
super.onReceivedError(view, request, error);
}
/*** WebView ssl 访问证书出错,handler.cancel()取消加载,handler.proceed()对然错误也继续加载*/
@Override
publicvoidonReceivedSslError(WebView view, SslErrorHandler handler, SslError error){
super.onReceivedSslError(view, handler, error);
}
}
三、与JS交互
1、Android调用js方法:2种方式
js方法:
functioncallJS(){
alert("Android调用了JS的callJS方法");
}
(1)第一种方法:loadUrl
wvWebview.loadUrl("javascript:callJS()");
(2)第二种方法:evaluateJavascript
wvWebview.evaluateJavascript("javascript:callJS()",newValueCallback() {
@Override
publicvoidonReceiveValue(String value){
//此处为 js 返回的结果
}
});
因为该方法的执行不会使页面刷新,而第一种方法(loadUrl )的执行则会。Android 4.4 后才可使用
所以建议:两种方法混合使用,即Android 4.4以下使用方法1,Android 4.4以上方法2
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
wvWebview.evaluateJavascript("javascript:callJS()",newValueCallback() {
@Override
publicvoidonReceiveValue(String value){
//此处为 js 返回的结果
}
});
}else{//Android 4.4 前使用该方法
wvWebview.loadUrl("javascript:callJS()");
}
2、js调用Android方法:3种方式
(1)第一种方法:addJavascriptInterface
优点:使用简单
缺点:存在严重的漏洞问题
// js调用方式
function callAndroid(){
test.hello("js调用了android中的hello方法");
}
//通过WebView设置Android类与JS代码的映射
wvWebview.addJavascriptInterface(new AndroidtoJs(), "test");
// 定义JS需要调用的方法
public class AndroidtoJs extends Object {
// 被JS调用的方法必须加入@JavascriptInterface注解
@JavascriptInterface
public void hello(String msg) {
System.out.println("JS调用了Android的hello方法");
}
}
(2)第二种方法:通过 WebViewClient 的shouldOverrideUrlLoading ()方法回调拦截 url
//js调用
function callAndroid(){
document.location="js://webview?arg1=1&arg2=222";
}
// andorid
// 在Android通过WebViewClient复写shouldOverrideUrlLoading ()
public class MyWebViewClient extends WebViewClient {
/**
* 是否在 WebView 内加载页面
*/
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(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);
}
}
(3)第三种方法:通过 WebChromeClient 的onJsAlert()、onJsConfirm()、onJsPrompt()方法回调拦截JS对话框alert()、confirm()、prompt() 消息
//js调用
function clickprompt(){
var result = prompt("js://demo?arg1=111&arg2=222");
alert("demo" + result);
}
//android定义
public class MyWebChromeClient extends WebChromeClient {
@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);
}
}
作者:斌林诚上
链接:https://www.jianshu.com/p/3dc06c3dfb7d