Android Hybrid 学习过程 四 WebView所有相关类使用说明_android webview所有的dom-程序员宅基地

技术标签: hybrid  android  Android相关  

因为关于WebView的相关细节还有很多,我就不一一写例子说明,一口气全写出来凭注释说明了

1.WebSetting

用于配置WebVIew的类

        WebSettings webSettings = mWebView.getSettings();
        if (webSettings == null) return;
        //设置字体缩放倍数,默认100
        webSettings.setTextZoom(100);
        // 支持 Js 使用
        webSettings.setJavaScriptEnabled(true);
        // 开启DOM缓存
        webSettings.setDomStorageEnabled(true);
        // 开启数据库缓存
        webSettings.setDatabaseEnabled(true);
        // 支持自动加载图片
        webSettings.setLoadsImagesAutomatically(hasKitkat());
        // 设置 WebView 的缓存模式
        webSettings.setCacheMode(WebSettings.LOAD_DEFAULT);
        // 支持启用缓存模式
        webSettings.setAppCacheEnabled(true);
        // 设置 AppCache 最大缓存值(现在官方已经不提倡使用,已废弃)
        webSettings.setAppCacheMaxSize(8 * 1024 * 1024);
        // Android 私有缓存存储,如果你不调用setAppCachePath方法,WebView将不会产生这个目录
        webSettings.setAppCachePath(getCacheDir().getAbsolutePath());
        // 数据库路径
        if (!hasKitkat()) {
            webSettings.setDatabasePath(getDatabasePath("html").getPath());
        }
        // 关闭密码保存提醒功能
        webSettings.setSavePassword(false);
        // 支持缩放
        webSettings.setSupportZoom(true);
        // 设置 UserAgent 属性
        webSettings.setUserAgentString("");
        // 允许加载本地 html 文件/false
        webSettings.setAllowFileAccess(true);
        // 允许通过 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);

        /**
         *  关于缓存目录:
         *
         *  我自测发现以下规律,如果你有涉及到目录操作,需要自己做下验证。
         *  Android 4.4 以下:/data/data/包名/cache
         *  Android 4.4 - 5.0:/data/data/包名/app_webview/cache/
         */

2.WebViewClient

因为Android4.4开始可以使用Chrome作为WebView的内核,所以关于这个WebViewClient,还有一个WebChromeClient

    private void initListener() {
        mWebView.setWebViewClient(new SafeWebViewClient());
        mWebView.setWebChromeClient(new SafeWebChromeClient());
    }

    public class SafeWebViewClient extends WebViewClient {
    

        /**
         * 当WebView得页面Scale值发生改变时回调
         */
        @Override
        public void onScaleChanged(WebView view, float oldScale, float newScale) {
            super.onScaleChanged(view, oldScale, newScale);
        }

        /**
         * 是否在 WebView 内加载页面
         *
         * @param view
         * @param url
         * @return
         */
        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url) {
            view.loadUrl(url);
            return true;
        }

        /**
         * WebView 开始加载页面时回调,一次Frame加载对应一次回调
         *
         * @param view
         * @param url
         * @param favicon
         */
        @Override
        public void onPageStarted(WebView view, String url, Bitmap favicon) {
            super.onPageStarted(view, url, favicon);
        }

        /**
         * WebView 完成加载页面时回调,一次Frame加载对应一次回调
         *
         * @param view
         * @param url
         */
        @Override
        public void onPageFinished(WebView view, String url) {
            super.onPageFinished(view, url);
        }

        /**
         * WebView 加载页面资源时会回调,每一个资源产生的一次网络加载,除非本地有当前 url 对应有缓存,否则就会加载。
         *
         * @param view WebView
         * @param url  url
         */
        @Override
        public void onLoadResource(WebView view, String url) {
            super.onLoadResource(view, url);
        }

        /**
         * WebView 可以拦截某一次的 request 来返回我们自己加载的数据,这个方法在后面缓存会有很大作用。
         *
         * @param view    WebView
         * @param request 当前产生 request 请求
         * @return WebResourceResponse
         */
        @Override
        public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
            return super.shouldInterceptRequest(view, request);
        }

        /**
         * WebView 访问 url 出错
         *
         * @param view
         * @param request
         * @param error
         */
        @Override
        public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
            super.onReceivedError(view, request, error);
        }

        /**
         * WebView ssl 访问证书出错,handler.cancel()取消加载,handler.proceed()对然错误也继续加载
         *
         * @param view
         * @param handler
         * @param error
         */
        @Override
        public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
            super.onReceivedSslError(view, handler, error);
        }
    }

    public class SafeWebChromeClient extends WebChromeClient {
    

        @Override
        public boolean onConsoleMessage(ConsoleMessage consoleMessage) {
            return super.onConsoleMessage(consoleMessage);
        }

        /**
         * 当前 WebView 加载网页进度
         *
         * @param view
         * @param newProgress
         */
        @Override
        public void onProgressChanged(WebView view, int newProgress) {
            super.onProgressChanged(view, newProgress);
        }

        /**
         * Js 中调用 alert() 函数,产生的对话框
         *
         * @param view
         * @param url
         * @param message
         * @param result
         * @return
         */
        @Override
        public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
            return super.onJsAlert(view, url, message, result);
        }

        /**
         * 处理 Js 中的 Confirm 对话框
         *
         * @param view
         * @param url
         * @param message
         * @param result
         * @return
         */
        @Override
        public boolean onJsConfirm(WebView view, String url, String message, JsResult result) {
            return super.onJsConfirm(view, url, message, result);
        }

        /**
         * 处理 JS 中的 Prompt对话框
         *
         * @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) {
            return super.onJsPrompt(view, url, message, defaultValue, result);
        }

        /**
         * 接收web页面的icon
         *
         * @param view
         * @param icon
         */
        @Override
        public void onReceivedIcon(WebView view, Bitmap icon) {
            super.onReceivedIcon(view, icon);
        }

        /**
         * 接收web页面的 Title
         *
         * @param view
         * @param title
         */
        @Override
        public void onReceivedTitle(WebView view, String title) {
            super.onReceivedTitle(view, title);
        }

    }

3.Js注入漏洞填坑

关于JS注入存在的安全问题,通过以下自定义WebView的代码能够填坑

public class SafeWebView extends WebView {
    

    public SafeWebView(Context context) {
        super(context);
        removeSearchBox();
    }

    public SafeWebView(Context context, AttributeSet attrs) {
        super(context, attrs);
        removeSearchBox();
    }

    public SafeWebView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        removeSearchBox();
    }

    /**
     * 移除系统注入的对象,避免js漏洞
     * <p>
     * https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-1939
     * https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-7224
     */
    private void removeSearchBox() {
        super.removeJavascriptInterface("searchBoxJavaBridge_");
        super.removeJavascriptInterface("accessibility");
        super.removeJavascriptInterface("accessibilityTraversal");
    }

    public static void disableAccessibility(Context context) {
        if (Build.VERSION.SDK_INT == 17/*4.2 (Build.VERSION_CODES.JELLY_BEAN_MR1)*/) {
            if (context != null) {
                try {
                    AccessibilityManager am = (AccessibilityManager) context.getSystemService(Context.ACCESSIBILITY_SERVICE);
                    if (!am.isEnabled()) {
                        //Not need to disable accessibility
                        return;
                    }

                    Method setState = am.getClass().getDeclaredMethod("setState", int.class);
                    setState.setAccessible(true);
                    setState.invoke(am, 0);/**{@link AccessibilityManager#STATE_FLAG_ACCESSIBILITY_ENABLED}*/
                } catch (Exception ignored) {
                    ignored.printStackTrace();
                }
            }
        }
    }

    @Override
    public void setOverScrollMode(int mode) {
//        try {
    
//            super.setOverScrollMode(mode);
//        } catch (Throwable e) {
    
//            e.printStackTrace();
//        }

        try {
            super.setOverScrollMode(mode);
        } catch (Throwable e) {
            String trace = Log.getStackTraceString(e);
            if (trace.contains("android.content.pm.PackageManager$NameNotFoundException")
                    || trace.contains("java.lang.RuntimeException: Cannot load WebView")
                    || trace.contains("android.webkit.WebViewFactory$MissingWebViewPackageException: Failed to load WebView provider: No WebView installed")) {
                e.printStackTrace();
            } else {
                throw e;
            }
        }
    }

    @Override
    public boolean isPrivateBrowsingEnabled() {
        if (Build.VERSION.SDK_INT == Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1 && getSettings() == null) {
            return false;
        } else {
            return super.isPrivateBrowsingEnabled();
        }
    }
}

参考文章

https://www.jianshu.com/p/fd61e8f4049e

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/z979451341/article/details/68485761

智能推荐

数据结构实验之栈与队列四:括号匹配_数据结构_习题三_栈和队列04:括号匹配 c++描述 给定一个字符串,字符串只包含两种-程序员宅基地

文章浏览阅读384次。数据结构实验之栈与队列四:括号匹配Time Limit:1000 msMemory Limit:65536 KiBSubmitStatisticProblem Description给你一串字符,不超过50个字符,可能包括括号、数字、字母、标点符号、空格,你的任务是检查这一串字符中的( ) ,[ ],{ }是否匹配。Input输入数据有多组,处理到文件结束。..._数据结构_习题三_栈和队列04:括号匹配 c++描述 给定一个字符串,字符串只包含两种

CVPR NTIRE 2022|双目超分辨率挑战赛开赛-程序员宅基地

文章浏览阅读1.1k次。编辑丨极市平台NTIRE英文全称是New Trends in Image Restoration and Enhancement,也就是“图像恢复与增强的新趋势”,是近年来计算机图像恢复领..._new trends in image restoration and enhancement

2020年最新最全的前端面试题整理----原生JS篇_创建一个空对象 data,并使用 validator 对象创建了一个代理 proxy。 当我们通过代-程序员宅基地

文章浏览阅读1.7k次,点赞7次,收藏21次。前言原生JS篇JS是一种什么样的语言?解释性脚本语言,代码不进行预编译主要用来向HTML页面添加交互行为可以直接嵌入HTML页面,但单独写成JS文件有利于结构和行为的分离跨平台性,在绝大多数浏览器的支持下,可以在多种平台下运行:linux、windowsJS数据类型有哪些?栈: (原始数据) string/number/boolean/null/undefined/symbol堆: (引用数据类型)object(array和函数属于object)数据类型一共7(6种基本类型+1种引用_创建一个空对象 data,并使用 validator 对象创建了一个代理 proxy。 当我们通过代

类加载器调用dex文件_d:\app\myapplication11\app\build\intermediates\pro-程序员宅基地

文章浏览阅读308次,点赞4次,收藏5次。因为DexClassLoader 参数需要一个文件路径 但是assets 中的文件并不是一个普通的文件路径,而是一个封装在 APK 中的资源。因此,你必须先将 dex 文件从 assets 复制到设备上的一个可访问的目录,然后再使用 DexClassLoader 加载它。新建了两个脚本 loadTest NetTool。将dex文件复制到另一个工程的assets目录下。jadx查看dex文件的结构。_d:\app\myapplication11\app\build\intermediates\project_dex_archive\debug\out

使用docker部署hyperf_docker开发hyperf-程序员宅基地

文章浏览阅读846次。项目需要用到高并发,选用swoole模式的hyperf框架,由于win下不支持协程,故在docker中运行。_docker开发hyperf

20 ubuntu 中科大源_ubuntu 16.04 LTS 修改 国内源(以中科大源为例)-程序员宅基地

文章浏览阅读277次。国内有很多ubuntu的源,包括:网易源(这个之前用过,速度很快的),阿里源,还有很多教育网的源,如:清华源,中科大源。这里要下载的是中科大ubuntu16.04的源列表,可以在这里获得:https://lug.ustc.edu.cn/repogen/编辑/etc/apt/sources.list文件, 在文件最前面添加以下条目(操作前请做好相应备份):打开终端,然后输sudo gedit /et..._20 apt ustc

随便推点

python水仙花数_ghpython_水仙花数-程序员宅基地

文章浏览阅读666次。今天咱们来看看老潘微博里的一个python小案例,求100到99999之间的所有水仙花数。所谓水仙花数,又被称为超完全数字不变数、自恋数、自幂数、阿姆斯壮数、阿姆斯特朗数。是指一个n位数(n≥3),它的每个位上的数字的n次幂之和等于它本身(153=1^3+5^3+3^3)。严格来说,只有3位数的3次幂数才成为水仙花数,水仙花数只是自幂数的一种。一位自幂数:独身数;二位自幂数:无;三位自幂..._python例2:水仙花数是指一个n位数(n≥3),它的每个位上的数字的n次幂之和等于它本

人大金仓数据库oracle_fdw扩展的使用-程序员宅基地

文章浏览阅读955次,点赞19次,收藏26次。oracle_fdw是KingbaseES的一个扩展插件,提供了一个外部数据包装器,可以使KingbaseES方便高效的访问oracle数据库。_oracle_fdw

流行开源许可证_流行的开源license-程序员宅基地

文章浏览阅读540次。如何为代码选择开源许可证,这是一个问题。世界上的开源许可证,大概有上百种。很少有人搞得清楚它们的区别。即使在最流行的六种:GPL、BSD、MIT、Mozilla、Apache和LGPL,如何在这之中做选择,也很复杂。乌克兰程序员 Paul Bagwell,画了一张分析图,说明应该怎么选择。这是我见过的最简单的讲解,只用两分钟,你就能搞清楚这六种许可证之间的最大区别。下面是阮一峰制作_流行的开源license

批量下载CMIP6数据的几种方法_cmip6数据下载-程序员宅基地

文章浏览阅读3.4k次,点赞8次,收藏42次。下载CMIP6数据的几种方法_cmip6数据下载

待整理内容-程序员宅基地

文章浏览阅读470次。1.牛顿法学习笔记:http://blog.csdn.net/itplus/article/details/21896453?source=1

Python元类是怎么创建一个类的?-程序员宅基地

文章浏览阅读331次,点赞5次,收藏3次。new。