老早之前就想总结下Webview相关的知识点了,因为互联网大潮中,很多APP都会使用到Webview,像那些不计其数的电商APP,无一例外的使用Webview;或者一些非电商APP中的像广告页面,注册协议页面都会用到;最后因为一些事情拖到现在才做,感觉事情真不能拖,越往后推越做不了,罪过罪过。
怎么总结Webview呢
1.简单介绍
2.WebView/WebViewClient/WebChromeClient api介绍
3.简单使用
4.JS调用Android本地
5.Android调用JS方法
6.缓存处理及性能优化
7.webview使用注意点
webview系列文章
Android之WebView/WebViewClient/WebChromeClient简介 API详述 【一】
Android之WebView/WebViewClient/WebChromeClient 使用样例 【二】
Android之WebView Android调用JS方法 JS调用Android方法 【三】
Android之WebView 使用注意点 JS注入漏洞问题 内存优化【五】
3.简单使用
在xml中添加
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<WebView
android:id="@+id/webview"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
然后在代码中进行如下编写
private void initWebview() {
/**
* webview相关设置的管理类,就像你家的大管家一样
*/
mSetting = mWebview.getSettings();
/**
* 处于安全性考虑,android默认不支持js
* 如果页面有js操作,一定要设置
*/
mSetting.setJavaScriptEnabled(true);
//设置允许js弹框
mSetting.setJavaScriptCanOpenWindowsAutomatically(true);
//在webview中启用或禁用内容URL访问,默认启用,可以通过Content provider去访问资源
mSetting.setAllowContentAccess(true);
//在webview中禁用或启用文件访问,默认启用,这里针对的是手机内存的文件,assets和res目录下的不受影响
mSetting.setAllowFileAccess(true);
//设置缓存模式
mSetting.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
//设置缓存路径
//Android 私有缓存存储,如果你不调用setAppCachePath方法,WebView将不会产生这个目录。
mSetting.setAppCachePath(MyApplication.getInstance().getCacheDir().getAbsolutePath());
//设置是否启用缓存(APPlication Cache),不过需要先设置好缓存路径,默认false
mSetting.setAppCacheEnabled(true);
//设置是否阻止加载网络图片 默认false
// mSetting.setBlockNetworkImage(false);
//设置是否自动加载图片 默认true
// mSetting.setLoadsImagesAutomatically(true);
//设置是否阻止加载所有网络资源 默认false
// mSetting.setBlockNetworkLoads(false);
//设置webview是否应使用其内置的缩放机制
mSetting.setBuiltInZoomControls(true);
//设置webview在使用内置缩放控件的时候是否显示屏幕缩放控件
mSetting.setDisplayZoomControls(false);
//设置是否启用DOM存储
mSetting.setDomStorageEnabled(true);
//设置webview是否能以概貌模式加载页面,即当页面内容宽度大于webview控件的宽度时
mSetting.setLoadWithOverviewMode(true);
// 设置 UserAgent 属性
mSetting.setUserAgentString("");
mWebViewClient = new MyWebViewClient();
mWebview.setWebViewClient(mWebViewClient);
// mChromeClient = new MyWebChromeClient();
// mWebview.setWebChromeClient(mChromeClient);
mWebview.setOnKeyListener(this);
//加载网络页面
mWebview.loadUrl("https://www.baidu.com");
//加载assets文件夹下的html
// mWebview.loadUrl("file:///android_asset/html/index.html");
//加载手机本地的html页面
// mWebview.loadUrl("content://com.android.htmlfileprovider/sdcard/test.html");
}
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
//点击返回键的时候如果有上一页就返回上一页,避免直接退出
if(keyCode == KeyEvent.KEYCODE_BACK && mWebview.canGoBack()){
mWebview.goBack();
return true;
}
return false;
}
public class MyWebChromeClient extends WebChromeClient{
private String TAG = "MyWebChromeClient";
@Override
public void onProgressChanged(WebView view, int newProgress) {
super.onProgressChanged(view, newProgress);
Log.e(TAG,"onProgressChanged newProgress="+newProgress);
}
@Override
public void onReceivedTitle(WebView view, String title) {
super.onReceivedTitle(view, title);
Log.e(TAG,"onReceivedTitle title="+title);
}
@Override
public void onReceivedIcon(WebView view, Bitmap icon) {
super.onReceivedIcon(view, icon);
Log.e(TAG,"onReceivedTitle icon="+icon.getByteCount());
}
/**
* htmlzhong <video/> 控件在未播放时,会展示成一张图片,html中可以通过poster属性来指定
* 如果没有指定poster属性,我们可以通过这个方法提供一个默认的海报图
* @return
*/
@Override
public Bitmap getDefaultVideoPoster() {
Log.e(TAG,"getDefaultVideoPoster");
return super.getDefaultVideoPoster();
}
/**
* 当全屏的视频正在缓冲时,通过此方法返回一个view
* @return
*/
@Override
public View getVideoLoadingProgressView() {
Log.e(TAG,"getVideoLoadingProgressView");
return super.getVideoLoadingProgressView();
}
@Override
public boolean onCreateWindow(WebView view, boolean isDialog, boolean isUserGesture, Message resultMsg) {
Log.e(TAG,"onCreateWindow");
return super.onCreateWindow(view, isDialog, isUserGesture, resultMsg);
}
@Override
public void onCloseWindow(WebView window) {
super.onCloseWindow(window);
Log.e(TAG,"onCloseWindow");
}
/**
* 接收js控制台消息
* @param consoleMessage
* @return
*/
@Override
public boolean onConsoleMessage(ConsoleMessage consoleMessage) {
Log.e(TAG,"onConsoleMessage");
return super.onConsoleMessage(consoleMessage);
}
/**
* 网页内容请求定位
* @param origin
* @param callback
*/
@Override
public void onGeolocationPermissionsShowPrompt(String origin, GeolocationPermissions.Callback callback) {
super.onGeolocationPermissionsShowPrompt(origin, callback);
Log.e(TAG,"onGeolocationPermissionsShowPrompt");
}
/**
* 请求定位取消了
*/
@Override
public void onGeolocationPermissionsHidePrompt() {
super.onGeolocationPermissionsHidePrompt();
Log.e(TAG,"onGeolocationPermissionsHidePrompt");
}
/**
* 当前页面进入了全屏模式,此时应用必须显示一个包含网页内容的自定义view
* @param view
* @param callback
*/
@Override
public void onShowCustomView(View view, CustomViewCallback callback) {
super.onShowCustomView(view, callback);
Log.e(TAG,"onShowCustomView");
}
/**
* 当前页面已退出全屏模式,但应用程序必须隐藏自定义view
*/
@Override
public void onHideCustomView() {
super.onHideCustomView();
Log.e(TAG,"onHideCustomView");
}
/**
* JS通知android显示一个警告对话框
* @param view
* @param url
* @param message
* @param result
* @return 返回true才有效 下面方法同理
*/
@Override
public boolean onJsAlert(WebView view, String url, String message, final JsResult result) {
Log.e(TAG,"onJsAlert");
if (!TextUtils.isEmpty(message)) {
//模拟显示一个对话框
Toast.makeText(MyApplication.getInstance(),message,Toast.LENGTH_SHORT).show();
AlertDialog.Builder build = new AlertDialog.Builder(MyApplication.getInstance());
build.setTitle(message);
build.setMessage(message);
build.setCancelable(true);
build.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
result.confirm();
}
});
build.create().show();
}
result.cancel();//调用这个方法,否则可能无效
return true;
}
/**
* JS通知android显示一个确认对话框
* @param view
* @param url
* @param message
* @param result
* @return
*/
@Override
public boolean onJsConfirm(WebView view, String url, String message, JsResult result) {
Log.e(TAG,"onJsConfirm");
return super.onJsConfirm(view, url, message, result);
}
/**
* JS通知android显示一个对话框让用户选择是否离开当前页面
* @param view
* @param url
* @param message
* @param result
* @return
*/
@Override
public boolean onJsBeforeUnload(WebView view, String url, String message, JsResult result) {
Log.e(TAG,"onJsBeforeUnload");
return super.onJsBeforeUnload(view, url, message, result);
}
/**
* JS通知android显示一个提示信息
* @param view
* @param url
* @param message
* @param defaultValue
* @param result
* @return
*/
@Override
public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
Log.e(TAG,"onJsPrompt");
return super.onJsPrompt(view, url, message, defaultValue, result);
}
/**
*当页面内容请求本地资源需要请求权限时回调,前提是该权限未被授权或取消
* @param request
*/
@Override
public void onPermissionRequest(PermissionRequest request) {
super.onPermissionRequest(request);
Log.e(TAG,"onPermissionRequest");
}
/**
* 申请权限被取消
* @param request
*/
@Override
public void onPermissionRequestCanceled(PermissionRequest request) {
super.onPermissionRequestCanceled(request);
Log.e(TAG,"onPermissionRequestCanceled");
}
/**
* 为 html <input type="file"> 显示文件选择器,返回false使用默认处理
* @param webView
* @param filePathCallback
* @param fileChooserParams
* @return
*/
@Override
public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {
Log.e(TAG,"onShowFileChooser");
return super.onShowFileChooser(webView, filePathCallback, fileChooserParams);
}
}
/**
* @Description TODO(处理webview的通知和请求)
* @author cxy
* @Date 2018/6/11 15:10
*/
public class MyWebViewClient extends WebViewClient {
private String TAG = "MyWebViewClient";
/**
* 设置不用系统浏览器打开,直接显示在当前Webview
* 在点击请求的是连接是才会调用
* 重写此方法返回true表明点击网页里面的链接还是在当前的webView里跳转,不跳到浏览器里边
* @param view
* @param request
* @return
*/
/*@Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
Log.i(TAG,"shouldOverrideUrlLoading Title="+view.getTitle()+""+request.getUrl().toString());
return true;
}*/
/**
* 这个方法在api24即7.0以后废弃了,上面那个方法在24后添加
* @param view
* @param url
* @return
*/
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
Log.i(TAG,"shouldOverrideUrlLoading Title="+view.getTitle()+",url="+url);
return true;
}
/**
* 页面开始加载时会回调 一次Frame加载对应一次回调
* 可以在这里显示加载动画,避免长时间的空白画面
* @param view
* @param url
* @param favicon
*/
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
Log.i(TAG,"onPageStarted url="+url);
}
/**
* 在加载页面资源时会调用,每一个资源(比如图片)的加载都会调用一次。
* @param view
* @param url
*/
@Override
public void onLoadResource(WebView view, String url) {
super.onLoadResource(view, url);
// Log.i(TAG,"onLoadResource url="+url);
}
/**
* 页面加载结束会回调
* @param view
* @param url
*/
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
Log.i(TAG,"onPageFinished url="+url);
}
/**
* 从服务器收到HTTP错误,错误的状态码大于等于400,任何资源的错误都会回调这个方法
* 比如遇到了404,我们可以设置显示一个本地的错误提示页面,要不然显示404页面对用户不友好
* @param view
* @param request
* @param errorResponse
*/
@Override
public void onReceivedHttpError(WebView view, WebResourceRequest request, WebResourceResponse errorResponse) {
super.onReceivedHttpError(view, request, errorResponse);
Log.i(TAG,"onReceivedHttpError errorResponse="+errorResponse.getStatusCode());
}
/**
* 加载网页时发生ssl错误
* webview默认不处理https请求
* 重写此方法可以让webView处理https请求
* @param view
* @param handler
* @param error
*/
@Override
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
super.onReceivedSslError(view, handler, error);
Log.i(TAG,"onReceivedSslError error="+error.getPrimaryError());
//表示等待正式响应 该决定会用于以后来响应SSL错误
handler.proceed();
//表示挂起连接,为默认方式
// handler.cancel();
}
/**
* 处理按键事件
* 系统按键或者shouldoverridekeyevent返回true 不回调此方法
* @param view
* @param event
*/
@Override
public void onUnhandledKeyEvent(WebView view, KeyEvent event) {
super.onUnhandledKeyEvent(view, event);
Log.i(TAG,"onUnhandledKeyEvent event="+event.getKeyCode());
}
/**
* 重写此方法才能够处理在浏览器中的按键事件
* 给应用一个机会处理按键事件,如果返回true,webview不处理该事件,
* 否则webview会一直处理,默认返回false
* @param view
* @param event
* @return
*/
@Override
public boolean shouldOverrideKeyEvent(WebView view, KeyEvent event) {
Log.i(TAG,"shouldOverrideKeyEvent event="+event.getKeyCode());
return super.shouldOverrideKeyEvent(view,event);
}
/**
* WebView 可以拦截某一次的 request 来返回我们自己加载的数据,这个方法在后面缓存会有很大作用。
*
* @param view WebView
* @param request 当前产生 request 请求
* @return WebResourceResponse
*/
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
return super.shouldInterceptRequest(view, request);
}
}
静待更新
后续篇章请前往Android之WebView/WebViewClient/WebChromeClient使用解析及Android与JS相互调用 【三】