Android WebView之WebViewClient和WebChromeClient

WebView里有两大常用的回调 WebViewClient和WebChromeClient,回调加起来大概有几十个,源码里面注释写的很完整,就简单翻译一下,刚好工作中会用到,也顺便熟悉一下这些回调。
先来看看WebViewClient的回调方法(本文基于API-26)


Android WebView之WebViewClient和WebChromeClient_第1张图片
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


Android WebView之WebViewClient和WebChromeClient_第2张图片
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 callback) {
}

Obtains a list of all visited history items, used for link coloring(没看懂是干嘛的)

public boolean onShowFileChooser(WebView webView, ValueCallback 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 getAcceptTypes 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.
         *
         * 
         * 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}
         * 
* * @return an Intent that supports basic file chooser sources. */ public abstract Intent createIntent(); }

告诉客户端显示一个文件选择器。
这被调用来处理带有“文件”输入类型的HTML表单,以响应用户按下“选择文件”按钮。
要取消请求,请调用filePathCallback.onReceiveValue(null)并返回true。

public void setupAutoFill(Message msg) { }

告诉客户端正在查看的页面有一个可自动填充的表单,用户希望设置一个配置文件。

你可能感兴趣的:(Android WebView之WebViewClient和WebChromeClient)