美文网首页安卓进阶Android收藏集
Android WebView之WebViewClient和We

Android WebView之WebViewClient和We

作者: guxuanyu | 来源:发表于2018-08-08 09:26 被阅读4904次

    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) { }
    

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

    相关文章

      网友评论

        本文标题:Android WebView之WebViewClient和We

        本文链接:https://www.haomeiwen.com/subject/yitrvftx.html