Android-WebView使用

开发中使用WebView加载url、html标签必不可少,比如广告、活动界面通过WebView加载具有实效性。下面介绍WebView使用方法。

webView.loadUrl(url);

loadUrl(url)这样可以直接加载网页,但此时是通过手机浏览器打开的网页,如果要使用WebView直接打开则需设置WebViewClient。

webView.setWebViewClient(new WebViewClient());

有关WebViewClient下面再详细介绍。

对于加载Url注意如下:
  1、如果是在线网址记得添加网络访问权限
  2、在线网址中,如果要使用webview打开,记得设置WebViewClient
  3、打开本地html文件时,是不需要设置WebViewClient,对应的asstes目录的url 为:file:///android_asset/xxxxx*

我们先来看如何根据需求设置webView属性,可以调用WebView.getSettings()获取设置WebView的WebSettings对象,通过WebSettings做属性配置,各配置说明如下:

        WebSettings webSettings = webView.getSettings();
        //设置开启javascript支持
        webSettings.setJavaScriptEnabled(true);
        //设置支持缩放
        webSettings.setSupportZoom(true);
        //开启缩放工具(会出现放大缩小的按钮)
        webSettings.setBuiltInZoomControls(true);
        //WebView两种缓存(网页、H5)方式,此处网页不缓存
        webSettings.setCacheMode(WebSettings.LOAD_NO_CACHE);
        //允许JS打开新窗口(默认false)
        webSettings.setJavaScriptCanOpenWindowsAutomatically(true);
        //打开本地缓存供JS调用
        webSettings.setDomStorageEnabled(true);
        //H5缓存内存大小(已过时,不必设置已可自动管理)
        //webSettings.setAppCacheMaxSize(1024 * 1024 * 8);
        //H5缓存路径
        String absolutePath = getApplicationContext().getCacheDir().getAbsolutePath();
        //H5缓存大小
        webSettings.setAppCachePath(absolutePath);
        //是否允许WebView访问内部文件(默认true)
        webSettings.setAllowFileAccess(true);
        //支持存储H5缓存
        webSettings.setAppCacheEnabled(true);
        //启动概述模式浏览界面,当页面宽度超过WebView显示宽度时,缩小页面适应WebView(默认false) 
        webSettings.setLoadWithOverviewMode(true);
        //支持手势缩放(如webView中需要手动输入用户名、密码等,则webview必须设置支持获取手势焦点)
        webView.requestFocusFromTouch();
        // 清除缓存
        webView.clearCache(true);
        // 清除缓存防止登录上次的账号
        CookieManager.getInstance().removeAllCookie();
Java调用JavaScript

java调用JavaScript中的函数很简单,只需要执行如下代码即可:

webView.loadUrl("javascript:toast()");

toast()是JS中方法。

JavaScript调用Java

三个步骤:
  1.调用WebSettings的setJavaScriptEnabled方法使支持JavaScript调用。
  2.调用WebView的addJavascriptInterface方法将应用中的Java对象暴露给JavaScript;
  3.在JavaScript脚本中调用步骤二暴露出来的Java对象的方法。

在webView.addJavascriptInterface(new JsBradge(), "android");实现;其中JsBradge()中是申明了JS可调用的本地方法,“android”是与JS协商的对象名称,JS端可通过android.toastMessage(" ")调用Java方法。
注:如下需加上@JavascriptInterface注解,避免引起WebView远程代码执行漏洞。

    public class JsBradge {
        @JavascriptInterface
        public void toastMessage(String message) {
            Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show();
        }
    }
WebViewClient

WebViewClient可以拿到WebView在访问网络各个阶段的回调,包括加载前后,失败等(以下注释来源"启舰"博客)

/** 
 * 在开始加载网页时会回调 
 */  
public void onPageStarted(WebView view, String url, Bitmap favicon)   
/** 
 * 在结束加载网页时会回调 
 */  
public void onPageFinished(WebView view, String url)  
/** 
 * 拦截 url 跳转,在里边添加点击链接跳转或者操作 
 */  
public boolean shouldOverrideUrlLoading(WebView view, String url)  
/** 
 * 加载错误的时候会回调,在其中可做错误处理,比如再请求加载一次,或者提示404的错误页面 
 */  
public void onReceivedError(WebView view, int errorCode,String description, String failingUrl)  
/** 
 * 当接收到https错误时,会回调此函数,在其中可以做错误处理 
 */  
public void onReceivedSslError(WebView view, SslErrorHandler handler,SslError error)  
/** 
 * 在每一次请求资源时,都会通过这个函数来回调 
 */  
public WebResourceResponse shouldInterceptRequest(WebView view,  String url) {  
    return null;  
}  

以上可以根据需求做相应处理,其中shouldOverrideUrlLoading方法会在加载超链接时回调过来,当需要WAP与原生互调等劫持URL时用到,重写该方法然后return true即可,当不需要劫持在else中重新loadUrl(url)即可。

            // 当点击链接时,希望覆盖而不是打开新窗口
            @Override
            public boolean shouldOverrideUrlLoading(WebView view, String url) {
                // showProgressDlg();
                // 拦截抢购商品,跳回APP抢购商品详情
                if (url.contains("proId") && url.contains("qgDetail.html")) {

                    String actid = url.split("\\?")[1].split("&")[0].split("=")[1];

                    ActivityController.startActProductDetailActivity(WebActivity.this, actid, "");

                } else if (url.contains("goodDetail.html") && url.contains("proId")) {

                    String id = url.split("\\?")[1].split("&")[0].split("=")[1];

                    ActivityController.startGoodsDetailActivity(WebActivity.this, id);
                } else {
                    view.loadUrl(url);
                }
                return true;
            }
WebChromeClient

可以在其中加载进度条,获取链接的标题等方法。

/**
 * 当网页调用alert()来弹出alert弹出框前回调,用以拦截alert()函数
 */
public boolean onJsAlert(WebView view, String url, String message,JsResult result)
/**
 * 当网页调用confirm()来弹出confirm弹出框前回调,用以拦截confirm()函数
 */
public boolean onJsConfirm(WebView view, String url, String message,JsResult result)
/**
 * 当网页调用prompt()来弹出prompt弹出框前回调,用以拦截prompt()函数
 */
 public boolean onJsPrompt(WebView view, String url, String message,String defaultValue, JsPromptResult result) 
 /**
 * 打印 console 信息
 */
 public boolean onConsoleMessage(ConsoleMessage consoleMessage)
 /**
 * 通知程序当前页面加载进度
 */
 public void onProgressChanged(WebView view, int newProgress)

下面附上我项目里的一段代码,加载进度条跟获取Title:

            @Override
            public void onProgressChanged(WebView view, int newProgress) {
                super.onProgressChanged(view, newProgress);
                if (newProgress == 100) {
                    progressBar.setVisibility(View.GONE);
                } else {
                    if (progressBar.getVisibility() == View.GONE)
                        progressBar.setVisibility(View.VISIBLE);
                    progressBar.setProgress(newProgress);
                }
            }

            @Override
            public void onReceivedTitle(WebView view, String title) {
                setActivityTitle(title);
            }
webView加载html

当后台返回不是url而是一连串的html标签时,可以通过

webView.loadDataWithBaseURL(null, html , "text/html", "UTF-8", "");

之前可以设置:

            //水平不显示滚动条
            webView.setHorizontalScrollBarEnabled(false);
            //垂直不显示滚动条
            webView.setVerticalScrollBarEnabled(false); 

            //初始化压缩比例
            webView.setInitialScale(50);
            // webview自适应屏幕尺寸
            webView.getSettings().setSupportZoom(true);
            webView.getSettings().setUseWideViewPort(true);
            webView.getSettings().setLoadWithOverviewMode(true);
            //设置图片显示方式
            webView.getSettings().setLayoutAlgorithm(WebSettings.LayoutAlgorithm.SINGLE_COLUMN);

            // 设置背景色
            //webView.setBackgroundColor(0);

            webView.getSettings().setDefaultTextEncodingName("UTF-8");
            //设置图片最大尺寸,高度自适应;文字颜色、字体大小、行高、首行缩进两个字符
            // 包含去除img style 的js代码
            String head = "<html><head> <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"> <meta name " +
                    "=\"viewport\" content =\"width=device-width,initial-scale=1, maximum-scale=1, minimum-scale=1," +
                    " user-scalable=no\"/><style type=\"text/css\">" +
                    "p {font-size:14px;line-height:20px;color:#303030;text-indent:2em;} " +
                    "img{max-width:100% ;height:auto !important;} a {color:#3E62A6;}\\u007Fpre {font-size:9pt;line-height:12pt;font-family:Courier New,Arial;border:1px solid #ddd;border-left:5px solid #6CE26C;background:#f6f6f6;padding:5px;}</style></head>"
                    + "<script type=\"text/javascript\"charset=\"utf-8\">window.onload=function(){var imgArr=document.getElementsByTagName(\"img\");for(var i in imgArr){imgArr[i].removeAttribute(\"style\")}}</script>";

            html = head + "<body>" + html + "<script type=\"text/javascript\"charset=\"utf-8\">var imgArr=document.getElementsByTagName(\"img\");for(var i in imgArr){imgArr[i].removeAttribute(\"style\");</script>"
                    + "</body></html>";
回退事件处理

当回退时,若不监听回退键点击返回时不会回退到上一web界面,而是直接结束当前Activity,通过canGoBack判断是否可回退,goBack进行回退。代码如下:

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK && webView.canGoBack()) {
            if (webView.copyBackForwardList().getItemAtIndex(webView.copyBackForwardList().getSize() - 1).getUrl().contains("activity/201412/act_common.html")) {
                //解决活动重定向无法回退到原生界面
                return super.onKeyDown(keyCode, event);
            } else {
                webView.goBack();
                return true;
            }
        }
        return super.onKeyDown(keyCode, event);
    }

以上你看到copyBackForwardList方法,这个是为了解决重定向可以正确退出当前Activity而设置。
先说下问题,当你loadUrl(url1)时,web端将url1更换成了url2,所以显示出来的是url2界面。webview中copyBackForwardList是专门用来管理url栈的,但此时,不光url2入栈,url1也入栈了,所以当在url2界面时,canGoBack返回的也是true,当按回退键时就会回到url1(不会显示)然后马上又回到url2界面,这就是按回退无法finish当前Activity而陷入重新加载url2界面的原因和解决办法。

注意在拥有WebVie的Activity中需要在onDestory方法中销毁webView以防内存泄漏,代码如下:

    @Override
    protected void onDestroy() {
        //销毁webview,避免内在泄漏
        if (webView != null) {
            //移除webView确保Detach
            ViewGroup parent = (ViewGroup) webView.getParent();
            if (parent != null) {
                parent.removeView(webView);
            }
            webView.removeAllViews();
            webView.clearHistory();
            webView.destroy();
            webView = null;
        }
        super.onDestroy();
    }

参考:

WebView使用详解(二)——WebViewClient与常用事件监听
《Android高级进阶》——顾浩鑫/著

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

推荐阅读更多精彩内容