WebView全面总结

Webview在我们平时开发中十分常用,几乎项目里面都会有嵌套网页。但是Webview可不是像我们平时loadUrl()就完了,它还有很多属性方法我们平时可能就没有开发出来。

最基本功能使用:

//加载一个远程网页
webView.loadUrl("https://www.baidu.com");

// 加载assets中资源
webView.loadUrl("file:///android_asset/web.html");

//加载sdcard中资源
webView.loadUrl("content://com.android.htmlfileprovider/sdcard/test.html");
  • WebSettings类有哪些属性可以设置?
WebSettings webSettings = webView.getSettings();
//设置支持javascript
webSettings.setJavaScriptEnabled(true); 
//支持插件
webSettings.setPluginsEnabled(true); 

//设置自适应屏幕,两者合用
webSettings.setUseWideViewPort(true); //将图片调整到适合webview的大小 
webSettings.setLoadWithOverviewMode(true); // 缩放至屏幕的大小

webSettings.setTextZoom(100);//字体百分比,替代原API:setTextSize

//缩放操作
webSettings.setSupportZoom(true); //支持缩放,默认为true。是下面那个的前提。
webSettings.setBuiltInZoomControls(true); //设置内置的缩放控件。若为false,则该WebView不可缩放
webSettings.setDisplayZoomControls(false); //隐藏屏幕中的虚拟缩放按钮

webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK); //开启webview中缓存 
webSettings.setAllowFileAccess(true); //设置可以访问文件 
webSettings.setJavaScriptCanOpenWindowsAutomatically(true); //支持通过JS打开新窗口 
webSettings.setLoadsImagesAutomatically(true); //支持自动加载图片
webSettings.setBlockNetworkImage(true);  //阻塞图片加载
webSettings.setDefaultTextEncodingName("utf-8");//设置编码格式

//优先使用缓存
webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK); 
  • Webview属性
webView.clearCache(true);    清除缓存    
webView.clearHistory();     清除历史记录   
webView.reload();            重新加载
Https 加载 Http 混合模式

当 WebView 加载 https 的地址中有 http 的地址时(比如 https 地址含有 http 的图片) WebView 无法加载 http 的资源,可使用setMixedContentMode方法设置。

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            webSettings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
        }
  • 页面监听与拦截

1.WebViewClient

WebViewClient主要用来处理请求和加载页面监听。示例如下:

public class MyWebViewClient extends WebViewClient {
    private Context context;

    public MyWebViewClient(Context context) {
        this.context = context;
    }

    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
        //用户可选择是否拦截加载 URL
        //如果返回值为 true,拦截 WebView 加载 url,false 允许 WebView 加载 url
        //所以在实际项目中,可以在这里处理自定义的一些跳转协议。

        if (url.startsWith("tel:")) {  //比如点击到已经定义好的 url 协议 电话号码 tel:// 时,那么可以在这里做拦截,跳转到系统拨号界面。
            Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
            context.startActivity(intent);
            return true;
        }
        return super.shouldOverrideUrlLoading(view, url);
    }

    @Override
    public void onPageStarted(WebView view, String url, Bitmap favicon) {
        //开始载入页面调用的
        super.onPageStarted(view, url, favicon);
    }

    @Override
    public void onPageFinished(WebView view, String url) {
        //在页面加载结束时调用
        super.onPageFinished(view, url);
    }

    @Override
    public void onLoadResource(WebView view, String url) {
        //在加载页面资源时会调用,每一个资源(比如图片)的加载都会调用一次。
        super.onLoadResource(view, url);
    }

    @Override
    public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
        //App里面使用webview控件的时候遇到了诸如404这类的错误的时候,若也显示浏览器里面的那种错误提示页面就显得很丑陋了,那么这个时候我们的app就需要加载一个本地的错误提示页面
//                view.loadUrl("file:///android_assets/error_handle.html");
        super.onReceivedError(view, request, error);
    }

    @Override
    public void onReceivedHttpError(WebView view, WebResourceRequest request, WebResourceResponse errorResponse) {
        //响应服务器返回的 Http 错误,当一个 http 正常响应时,状态码会是 200,当状态码异常时可以用该方法监听。
        int code = errorResponse.getStatusCode();
        switch (code) {
            case 400:
                // 重新登录
                break;
        }
        super.onReceivedHttpError(view, request, errorResponse);
    }

    @Override
    public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
        //SSL 证书验证错误
        super.onReceivedSslError(view, handler, error);
    }
}
  • WebChromeClient

WebChromeClient主要辅助WebView处理Javascript的对话框、网站图标、网站标题、加载进度等。

  public class MyWebChromeClient extends WebChromeClient {

    private Context context;

    public MyWebChromeClient(Context context) {
        this.context = context;
    }

    @Override
    public void onProgressChanged(WebView view, int newProgress) {
        //这个方法会在网页加载过程中多次触发,当 newProgress = 100 时,可以认为网页加载完成。这个方法比 onPageFinished 更为准确,一般用来实现自定义进度条加载。
        Log.i("minfo", "当前加载进度: " + newProgress);
        super.onProgressChanged(view, newProgress);
    }

    @Override
    public void onReceivedTitle(WebView view, String title) {
        //显示页面标题 title为该页面标题
        Log.i("minfo", "页面title: " + title);
        super.onReceivedTitle(view, title);
    }

    /**
     * 页面提示框
     * @param message alert 弹出窗口中的提示信息(提示或警告信息对话框,仅一个确认按钮)
     * @param result 向网页中的 Javascript 代码反馈本次操作结果(result.confirm 代表点击了确定按钮,result.cancel 代表点击了取消按钮)
     */
    @Override
    public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
        //页面提示框 onJsAlert()
        new AlertDialog.Builder(context)
                .setTitle("JsAlert")
                .setMessage(message)
                .setPositiveButton("确定", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        result.confirm();
                    }
                })
                .setCancelable(false)
                .show();

        return super.onJsAlert(view, url, message, result);
    }

    /**
     * 页面选择框
     * @param message confirm 弹出窗口中的提示信息(确认对话框,有确认、取消两个按钮)
     * @param result 向网页中的 Javascript 代码反馈本次操作结果(result.confirm 代表点击了确定按钮,result.cancel 代表点击了取消按钮)
     */
    @Override
    public boolean onJsConfirm(WebView view, String url, String message, JsResult result) {
        return super.onJsConfirm(view, url, message, result);
    }
}
  • Webview内存泄漏解决

1、在使用webview时不用xml布局中引用,在代码中创建并用viewgroup调用addView()的方式。
2、在使用Activity的onDestroy方法中,让webview加载空,移除webview,webview销毁并置null。

@Override
    protected void onDestroy() {
        if (mWebView != null) {
            mWebView.loadDataWithBaseURL(null, "", "text/html", "utf-8", null);
            mWebView.clearHistory();

            ((ViewGroup) mWebView.getParent()).removeView(mWebView);
            mWebView.destroy();
            mWebView = null;
        }
        super.onDestroy();
    }
  • Webview设置缓存机制
        WebSettings settings = webView.getSettings();
        //设置缓存路径
        String cacheDirPath = getFilesDir().getAbsolutePath()+"cache/";
        settings.setAppCachePath(cacheDirPath);
        //设置缓存大小
        settings.setAppCacheMaxSize(20*1024*1024);
        //开启AppCache存储机制
        settings.setAppCacheEnabled(true);
  • 启动指定浏览器

在Android程序中我们可以通过发送显式Intent来启动指定的浏览器。例如,启动手机自带浏览器。

         Intent intent =newIntent();        
         intent.setAction("android.intent.action.VIEW");    
         Uri content_url =Uri.parse("https://www.baidu.com");   
         intent.setData(content_url);           
         intent.setClassName("com.android.browser","com.android.browser.BrowserActivity");   
         startActivity(intent);

启动其他浏览器,只要修改以intent.setClassName(package,activity)中2个参数,对应的应用浏览器程序packagename和要启动的activity即可启动其他浏览器。

uc浏览器 com.uc.browser com.uc.browser.ActivityUpdate
opera浏览器 com.opera.mini.android com.opera.mini.android.Browser
qq浏览器 com.tencent.mtt com.tencent.mtt.MainActivity

Webview基本功能总结如上,最后,还有其他功能Webview与Android交互

问题:

  • WebView 的 addJavascriptInterface()的作用
webView.addJavascriptInterface(this, "android")

-定义一个与 JS 对象映射关系的 Android 类:AndroidtoJs:
1.定义 JS 需要调用的方法,被 JS 调用的方法必须加入@JavascriptInterface
注解。
2.通过 addJavascriptInterface()将 Java 对象映射到 JS 对象。

  • 前进 / 后退网页
//是否可以后退
Webview.canGoBack() 
//后退网页
Webview.goBack()

//是否可以前进                     
Webview.canGoForward()
//前进网页
Webview.goForward()

//以当前页面为准,前进或者后退到历史记录中指定的steps页面数
//如果steps为负数则为后退,正数则为前进
Webview.goBackOrForward(int steps)
  • 按系统back键怎么控制网页后退而不是直接关闭webview?

在当前展示Webview的Activity中处理Back事件,监听系统back键点击,在其中调用webview.goBack()方法。

public boolean onKeyDown(int keyCode, KeyEvent event) {
    if ((keyCode == KEYCODE_BACK) && mWebView.canGoBack()) { 
        mWebView.goBack();
        return true;
    }
    return super.onKeyDown(keyCode, event);
}
webview cookie管理

什么是cookie:最简单理解就是由http衍生出来的一种特殊的浏览器的缓存,特点是具有时效性、账户相关性、存储在客户端等。Android 中Cookie的管理相关:说到cookie的管理,其实本质上就是数据的存储问题。在早期的cookie是由CookieSyncManager进行管理的,但是在API 21 之后CookieSyncManager被抛弃了,换成了CookieManager来进行管理。

Android中Cookie的存储:项目中使用 WebView 其实会自动将 Cookie 保存在本地数据库中。保存是路径为 data/data/package_name/app_WebView/Cookies 虽然不是 .db 结尾的,实际就是一个 .db 文件

webview有一个CookieManager这个类,他是专门管理cookie的,这个类可以设置一个或多个cookie,而且当你在里面设置好cookie以后接口会自动根据你设置时的url来使用。

public class CookieHandle {
    private CookieManager cookieManager;

    public void setCookies(Activity context, String url) {
        HttpCookie cookie = new HttpCookie("name", "value");
        cookie.setDomain("baidu.com"); //设置域名
        cookie.setPath("files"); //设置域名下的path
        cookie.setMaxAge(10000);  //设置过期时间

        // 调用CookieManager 的方法设置cookie
        // 具有相同的 host 和 path 和 name 的任何现有的 Cookie 将会被替换为新的 Cookie
        CookieManager.getInstance().setCookie(url, cookie.toString());
    }

    /**
     * 删除cookie操作:底层实现是异步清除数据库的记录
     */
    public void deleteCookie() {
        CookieManager.getInstance().removeAllCookies(null);
        CookieManager.getInstance().flush(); //这个flush()方法就是立即同步cookie的操作
    }

 /**
     * 设置是否保存cookie
     */
    fun setAcceptCookies(accept: Boolean) {
        CookieManager.getInstance().setAcceptCookie(accept)
    }

    /**
     * 清理cookie
     */
    fun clearCookie() {
        CookieManager.getInstance().removeAllCookie()
    }

    /**
     * 获取某个网站cookie
     */
    fun getCookie(url: String) {
        CookieManager.getInstance().getCookie(url)
    }

    /**
     * 同步cookie
     */
    @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
    fun synchCookie() {
        CookieManager.getInstance().flush()
    }

    /**
     * 清理webview网站账号密码
     */
    @RequiresApi(Build.VERSION_CODES.ECLAIR_MR1)
    fun clearPasswords(context: Context) {
        var db = WebViewDatabase.getInstance(context)
        db.clearUsernamePassword()
        db.clearHttpAuthUsernamePassword()
    }

    @RequiresApi(Build.VERSION_CODES.ECLAIR_MR1)
    fun clearDataBase() {
        WebStorage.getInstance().deleteAllData()
    }

    fun clearCache() {
        WebIconDatabase.getInstance().removeAllIcons()
    }

    /**
     * 清理缓存
     */
    fun clearAllData(context: Context) {
        clearCookie()
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ECLAIR_MR1) {
            clearPasswords(context)
            clearDataBase()
        }
        clearCache()
    }
}

注:只有cookie的domain和path与请求的URL匹配才会发送这个cookie。

WebView调用本地相册

1.重写方法(WebChromeClient类中的onShowFileChooser)

    public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {
        mUploadCallbackAboveL = filePathCallback;
        Intent i = new Intent(Intent.ACTION_GET_CONTENT);
        i.addCategory(Intent.CATEGORY_OPENABLE);
        i.setType("image/*");
        context.startActivityForResult(Intent.createChooser(i, "File Browser"), FILECHOOSER_RESULTCODE);
        return true;
    }

2.在调起的activity中重写onActivityResult方法获取data中选择的本地文件。

参考:
https://juejin.cn/post/7152861867973705758
https://www.jianshu.com/p/0d1bd9443caa

Github代码地址:

https://github.com/running-libo/Webview

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,634评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,951评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,427评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,770评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,835评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,799评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,768评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,544评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,979评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,271评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,427评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,121评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,756评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,375评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,579评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,410评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,315评论 2 352

推荐阅读更多精彩内容