Android WebView之WebViewClient和We
WebView里有两大常用的回调 WebViewClient和WebChromeClient,回调加起来大概有几十个,源码里面注释写的很完整,就简单翻译一下,刚好工作中会用到,也顺便熟悉一下这些回调。
先来看看WebViewClient的回调方法(本文基于API-26)
WebViewClient
下面介绍模式为代码在上介绍在下,例如
代码
此段代码简介
希望读者不要看着看着就上下看乱了
从头开始看,shouldOverrideUrlLoading(WebView view, String url)
@Deprecated
public boolean shouldOverrideUrlLoading(WebView view, String url) {
return false;
}
已不推荐使用,当前的WebVIEW中要加载新的URL时,给宿主应用程序一个接管控件的机会。如果没有提供WebViewClient,默认情况下,WebView将要求Activity Manager为URL选择合适的处理程序。如果提供了WebViewClient,返回true意味着宿主应用程序处理URL,而返回false意味着当前WebVIEW处理URL。这种方法不使用POST“方法”请求。
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
return shouldOverrideUrlLoading(view, request.getUrl().toString());
}
作用和上面一样,但是参数由String url
换成了WebResourceRequest request
新版本推荐使用,此方法在POST请求不会调用。该方法会在加载非HTTP模式的子ifream调用,因此强烈地不建议用方法内的请求URL无条件地调用WebView loadURL(String)
,然后返回true,因为这将使WebVIEW试图加载非HTTP URL,从而失败。(参数里的WebResourceRequest
是什么?打开AS点进去看一看就知道啦)
public void onPageStarted(WebView view, String url, Bitmap favicon) {
}
通知主程序页面开始加载。此方法当每个带iframe或者framesets 的主frame加载一个页面调用仅一次。也就是说内嵌的frame改变例如点击一个目标是iframe的链接,onPageStarted 将不会被调用。fragment导航也不会调用。
public void onPageFinished(WebView view, String url) {
}
通知主程序页面加载完成,此方法只会在主调用。当此方法调用,页面的图片有可能还没更新完成。如果想获取图片更新的通知,去使用 WebView.PictureListener # onNewPicture
public void onLoadResource(WebView view, String url) {
}
通知主程序WebView将加载指定url的资源
public void onPageCommitVisible(WebView view, String url) {
}
HTTP的body标签加载前调用,仅在主frame调用。
@Deprecated
public WebResourceResponse shouldInterceptRequest(WebView view,
String url) {
return null;
}
(此方法已不推荐使用,推荐下面的)通知主程序资源请求并可以返回资源数据。如果返回null,则WebView将和平时一样继续加载资源。如果非空,返回可以使用的数据。注意:此方法运行在非ui线程,请谨慎访问私有数据或view。
public WebResourceResponse shouldInterceptRequest(WebView view,
WebResourceRequest request) { return shouldInterceptRequest(view, request.getUrl().toString());
}
作用和上面一样,推荐用这个
@Deprecated
public void onTooManyRedirects(WebView view, Message cancelMsg,
Message continueMsg) {
cancelMsg.sendToTarget();
}
已弃用,没有替代方法,不用看了
然后源码里提供了一堆状态码供下面函数使用(参数errorCode)
public static final int ERROR_UNKNOWN = -1;
/** Server or proxy hostname lookup failed */
public static final int ERROR_HOST_LOOKUP = -2;
/** Unsupported authentication scheme (not basic or digest) */
public static final int ERROR_UNSUPPORTED_AUTH_SCHEME = -3;
/** User authentication failed on server */
public static final int ERROR_AUTHENTICATION = -4;
/** User authentication failed on proxy */
public static final int ERROR_PROXY_AUTHENTICATION = -5;
/** Failed to connect to the server */
public static final int ERROR_CONNECT = -6;
/** Failed to read or write to the server */
public static final int ERROR_IO = -7;
/** Connection timed out */
public static final int ERROR_TIMEOUT = -8;
/** Too many redirects */
public static final int ERROR_REDIRECT_LOOP = -9;
/** Unsupported URI scheme */
public static final int ERROR_UNSUPPORTED_SCHEME = -10;
/** Failed to perform SSL handshake */
public static final int ERROR_FAILED_SSL_HANDSHAKE = -11;
/** Malformed URL */
public static final int ERROR_BAD_URL = -12;
/** Generic file error */
public static final int ERROR_FILE = -13;
/** File not found */
public static final int ERROR_FILE_NOT_FOUND = -14;
/** Too many requests during this load */
public static final int ERROR_TOO_MANY_REQUESTS = -15;
/** Resource load was cancelled by Safe Browsing */
public static final int ERROR_UNSAFE_RESOURCE = -16;
@Deprecated
public void onReceivedError(WebView view, int errorCode,
String description, String failingUrl) {
}
(不推荐使用)向主机应用程序报告错误。这些错误是不可恢复的(即主资源不可用)。参数对应于上面那些错误码。
public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
if (request.isForMainFrame()) {
onReceivedError(view,
error.getErrorCode(), error.getDescription().toString(),request.getUrl().toString());
}
}
向主机应用程序报告Web资源加载错误。这些错误通常表示无法连接到服务器。请注意,与回调版本的不推荐版本不同,新版本将被调用任何资源(IFRAME、图像等),而不仅仅是主页。因此,建议在该回调中执行最小所需的工作。
public void onReceivedHttpError(
WebView view, WebResourceRequest request, WebResourceResponse errorResponse) {
}
通知主机应用程序在加载资源时从服务器接收到HTTP错误。HTTP错误的状态代码>=400。此回调将调用任何资源(IFRAME、图像等),而不只是针对主页。因此,建议在该回调中执行最小所需的工作。注意,服务器响应的内容不能在errorCode参数中提供。
public void onFormResubmission(WebView view, Message dontResend,
Message resend) {
dontResend.sendToTarget();
}
当浏览器重新提交表单调用,默认是不会重新发送的。
public void doUpdateVisitedHistory(WebView view, String url,
boolean isReload) {
}
通知主程序更新浏览记录到数据库。
public void onReceivedSslError(WebView view, SslErrorHandler handler,
SslError error) {
handler.cancel();
}
通知主机应用程序在加载资源时发生SSL错误。宿主应用程序必须调用handler.cancel()或者 handler.proceed()。注意,可以保留该决定,以响应将来的SSL错误。默认行为是取消加载。
public void onReceivedClientCertRequest(WebView view, ClientCertRequest request) {
request.cancel();
}
通知主机应用程序处理SSL客户端证书请求。如果需要,主机应用程序负责显示UI并提供密钥。有三种方式来响应:proceed(), cancel()或ignore()。WebVIEW将调用响应存储在内存中(对于应用程序的生命周期)如果proceed() 或 cancel()被调用并且个对同样的主机:端口不会再次调用onReceivedClientCertRequest()。如果调用ignore(),WebVIEW不会存储响应。要注意多层chromium网络栈可能会缓存相应,所以最好的行为就是忽略(ignore)。这个方法在UI线程上被调用。在回调期间,连接被挂起。
public void onReceivedHttpAuthRequest(WebView view,
HttpAuthHandler handler, String host, String realm) {
handler.cancel();
}
通知主机应用程序WebVIEW接收到HTTP身份验证请求。宿主应用程序可以使用提供的HttpAuthHandler 来设置WebView 对请求的响应。默认行为是取消请求。
public boolean shouldOverrideKeyEvent(WebView view, KeyEvent event) {
return false;
}
给主机应用程序一个同步处理key event的机会,例如菜单快捷键事件需要以这种方式过滤。如果返回true,WebView 将不处理key event 。如果返回false,WebView将始终处理键事件,因此视图链中的超级节点都不会看到key event。默认行为返回false。
public void onScaleChanged(WebView view, float oldScale, float newScale) {
}
通知主机应用程序应用到WebVIEW的比例尺改变了。
public void onReceivedLoginRequest(WebView view, String realm,
String account, String args) {
}
通知主机应用程序请求自动登录用户已被处理。
public boolean onRenderProcessGone(WebView view, RenderProcessGoneDetail detail) {
return false;
}
通知宿主应用程序已经退出给定的WebVIEW的渲染过程。
return true如果宿主应用程序处理进程已退出的情况,否则,如果渲染过程崩溃,应用程序将崩溃,或者如果渲染过程被系统杀死则会被杀死。
WebViewClient看完了,下面看看WebChromeClient
WebChromeClient.PNG
public void onProgressChanged(WebView view, int newProgress) {}
通知主程序当前加载页面进度。这个方法有个妙用,可以参考https://www.jianshu.com/p/e320d6bb11e7
public void onReceivedTitle(WebView view, String title) {}
通知主程序document title变化。
public void onReceivedIcon(WebView view, Bitmap icon) {}
通知主程序当前页面有新的favicon。
public void onReceivedTouchIconUrl(WebView view, String url,
boolean precomposed) {}
通知主程序的apple-touch-icon的url。apple-touch-icon用于给苹果设备生成桌面快捷方式。
public void onShowCustomView(View view, CustomViewCallback callback) {};
public interface CustomViewCallback {
/**
* 当主程序拒绝自定义view时调用
*/
public void onCustomViewHidden();
}
通知主机应用程序当前页面已进入全屏模式。主应用程序必须在全屏幕模式下显示包含Web内容(视频或其他HTML内容)的自定义视图。也请参阅WebView里的“全屏支持”文档。
public void onHideCustomView() {}
通知主程序当前页面已经退出全屏模式。主程序需要隐藏自定义view。
public boolean onCreateWindow(WebView view, boolean isDialog,
boolean isUserGesture, Message resultMsg) {
return false;
}
请求主机应用程序创建一个新窗口。如果宿主应用程序选择尊重这个请求,它应该从这个方法返回true,创建一个新的WebView来托管窗口,将它插入到视图系统中,并以新的WebView作为参数将提供的resultMsg消息发送到它的目标。如果宿主应用程序选择不履行请求,则应该从该方法返回false。此方法的默认实现不执行任何操作,因此返回false。
public void onRequestFocus(WebView view) {}
此WebVIEW请求显示和焦点。这可能是由于另一WebVIEW在这个WebVIEW中打开一个链接并请求显示这个WebView。
public void onCloseWindow(WebView window) {}
通知主机应用程序关闭给定的WebVIEW,并在必要时从视图系统中删除它。在这一点上,WebCore已经停止了这个窗口中的任何加载,并删除了JavaScript中的任何互相访问能力。
public boolean onJsAlert(WebView view, String url, String message,
JsResult result) {
return false;
}
public boolean onJsConfirm(WebView view, String url, String message,
JsResult result) {
return false;
}
public boolean onJsPrompt(WebView view, String url, String message,
String defaultValue, JsPromptResult result) {
return false;
}
这仨是接收js三种对话框事件的,返回true则app处理,否则网页webview自己处理。
public boolean onJsBeforeUnload(WebView view, String url, String message,
JsResult result) {
return false;
}
告诉客户端显示一个对话框以确认导航离开当前页面。这是预先卸载JavaScript事件的结果。如果客户端返回true,WebVIEW将假定客户端将处理确认对话框并调用适当的JSREST方法。如果客户端返回false,则true值将返回到JavaScript以接受当前页面的导航。默认行为是返回false。将JSRESULT设置为true将导航离开当前页面,false将取消导航。
public void onGeolocationPermissionsShowPrompt(String origin,
GeolocationPermissions.Callback callback) {}
通知主机应用程序,来自指定来源的Web内容试图使用地理定位API,但目前没有为该源设置许可状态。宿主应用程序应该调用具有所需权限状态的指定回调。有关详细信息,请参阅GeolocationPermissions。
public void onGeolocationPermissionsHidePrompt() {}
如果上面那个权限取消会调用这个,因为没有权限,所以相关ui应该被隐藏。
public void onPermissionRequest(PermissionRequest request) {
request.deny();
}
通知主机应用程序Web内容请求访问指定资源的权限,并且当前未授予或拒绝权限。宿主应用程序必须调用PermissionRequest#grant(String[])或PermissionRequest#deny()。如果此方法未被重写,则拒绝该权限。
public void onPermissionRequestCanceled(PermissionRequest request) {}
通知主程序权限请求被取消。相关ui应该被隐藏。
@Deprecated
public void onConsoleMessage(String message, int lineNumber, String sourceID) { }
(不推荐使用,推荐下面的)向主机应用程序报告一个JavaScript控制台消息。ChromeClient 应该重写这个过程来处理日志消息,因为它们看起来合适。
public boolean onConsoleMessage(ConsoleMessage consoleMessage) {
// Call the old version of this function for backwards compatability.
onConsoleMessage(consoleMessage.message(), consoleMessage.lineNumber(),
consoleMessage.sourceId());
return false;
}
功能和上面一样,推荐这个。
public Bitmap getDefaultVideoPoster() {
return null;
}
当不播放时,视频元素由'poster' 图像表示。可以使用HTML中的视频标签的poster 属性来指定要使用的图像。如果属性不存在,则将使用默认poster 。此方法允许ChromeClient 提供默认图像。
public View getVideoLoadingProgressView() {
return null;
}
获取在全屏视频正在缓冲的同时显示的视图。宿主应用程序可以重写此方法,以提供包含旋转器或类似物的视图。
public void getVisitedHistory(ValueCallback<String[]> callback) {
}
Obtains a list of all visited history items, used for link coloring(没看懂是干嘛的)
public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback,
FileChooserParams fileChooserParams) {
return false;
}
第三个参数是个静态内部类,贴一下
public static abstract class FileChooserParams {
/** Open single file. Requires that the file exists before allowing the user to pick it. */
public static final int MODE_OPEN = 0;
/** Like Open but allows multiple files to be selected. */
public static final int MODE_OPEN_MULTIPLE = 1;
/** Like Open but allows a folder to be selected. The implementation should enumerate
all files selected by this operation.
This feature is not supported at the moment.
@hide */
public static final int MODE_OPEN_FOLDER = 2;
/** Allows picking a nonexistent file and saving it. */
public static final int MODE_SAVE = 3;
/**
* Parse the result returned by the file picker activity. This method should be used with
* {@link #createIntent}. Refer to {@link #createIntent} for how to use it.
*
* @param resultCode the integer result code returned by the file picker activity.
* @param data the intent returned by the file picker activity.
* @return the Uris of selected file(s) or null if the resultCode indicates
* activity canceled or any other error.
*/
public static Uri[] parseResult(int resultCode, Intent data) {
return WebViewFactory.getProvider().getStatics().parseFileChooserResult(resultCode, data);
}
/**
* Returns file chooser mode.
*/
public abstract int getMode();
/**
* Returns an array of acceptable MIME types. The returned MIME type
* could be partial such as audio/*. The array will be empty if no
* acceptable types are specified.
*/
public abstract String[] getAcceptTypes();
/**
* Returns preference for a live media captured value (e.g. Camera, Microphone).
* True indicates capture is enabled, false disabled.
*
* Use <code>getAcceptTypes</code> to determine suitable capture devices.
*/
public abstract boolean isCaptureEnabled();
/**
* Returns the title to use for this file selector, or null. If null a default
* title should be used.
*/
public abstract CharSequence getTitle();
/**
* The file name of a default selection if specified, or null.
*/
public abstract String getFilenameHint();
/**
* Creates an intent that would start a file picker for file selection.
* The Intent supports choosing files from simple file sources available
* on the device. Some advanced sources (for example, live media capture)
* may not be supported and applications wishing to support these sources
* or more advanced file operations should build their own Intent.
*
* <pre>
* How to use:
* 1. Build an intent using {@link #createIntent}
* 2. Fire the intent using {@link android.app.Activity#startActivityForResult}.
* 3. Check for ActivityNotFoundException and take a user friendly action if thrown.
* 4. Listen the result using {@link android.app.Activity#onActivityResult}
* 5. Parse the result using {@link #parseResult} only if media capture was not requested.
* 6. Send the result using filePathCallback of {@link WebChromeClient#onShowFileChooser}
* </pre>
*
* @return an Intent that supports basic file chooser sources.
*/
public abstract Intent createIntent();
}
告诉客户端显示一个文件选择器。
这被调用来处理带有“文件”输入类型的HTML表单,以响应用户按下“选择文件”按钮。
要取消请求,请调用filePathCallback.onReceiveValue(null)
并返回true。
public void setupAutoFill(Message msg) { }
告诉客户端正在查看的页面有一个可自动填充的表单,用户希望设置一个配置文件。