webview总结

一.webview加载白屏或者加载表格界面无法显示

什么都别管,先把这坨设置丢上去

        pullToRefreshWebView.getSettings().setBlockNetworkImage(false);
        pullToRefreshWebView.getSettings().setJavaScriptEnabled(true);
        pullToRefreshWebView.getSettings().setLayoutAlgorithm(WebSettings.LayoutAlgorithm.SINGLE_COLUMN);
        pullToRefreshWebView.setHorizontalScrollBarEnabled(false);
        pullToRefreshWebView.setHorizontalScrollbarOverlay(false);
        pullToRefreshWebView.getSettings().setBuiltInZoomControls(true);
        pullToRefreshWebView.getSettings().setUseWideViewPort(true);
        pullToRefreshWebView.getSettings().setLoadWithOverviewMode(true);
        pullToRefreshWebView.getSettings().setSavePassword(false);
        pullToRefreshWebView.getSettings().setSupportZoom(false);
        pullToRefreshWebView.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);
        pullToRefreshWebView.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
        pullToRefreshWebView.getSettings().setAppCacheEnabled(true);
        pullToRefreshWebView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
        pullToRefreshWebView.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
        pullToRefreshWebView.getSettings().setAllowFileAccess(true);
        pullToRefreshWebView.getSettings().setSaveFormData(false);
        pullToRefreshWebView.getSettings().setLoadsImagesAutomatically(true);
        pullToRefreshWebView.getSettings().setDomStorageEnabled(true);

二.webview与JS的交互
1. 调用js的方法, 前提设置.setJavaScriptEnabled(true); 必须的

    两种方式:  第一种通过webview.loadurl()  ,  第二种mWebView.evaluateJavascript();
  
    两种方法却别在于第一种会刷新界面,第二种只能在4.4以后使用,并且可以获取JS的返回值!
    
    loadurl()具体使用
     String open_id = SpUtils.getString(this, Constant.OPEN_ID, "");
      String userNmae = SpUtils.getString(this, Constant.USER_NAME, "");
      String userHead = SpUtils.getString(this, Constant.USER_HEAD, "");
      userinf_Url = "javascript:appLogin('" + open_id + "'," + "'" + userHead + "','" + userNmae + "')";
  appLogin是JS的方法名,open_id ,userHead ,userNmae 是相关参数! 也就是将整个方法拼接成一个字符串

  然后再webview加载完毕之后再去调用,pagefinished方法!
  @Override
            public void onPageFinished(WebView view, String url) {
                web.post(new Runnable() {
                    @Override
                    public void run() {
                        web.loadUrl(userinf_Url);
                    }
                });
            }
在某些动态获取值的时候,在移动端处理完数据之后需要再次传递,重新加载一次webview.reload()接可以再次调用方法!
也就是loadurl方法在调用JS方法的时候每次都需要刷新界面

 方法二此方法需要注意只有在4.4以上才能使用

  if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) {
  mWebView.evaluateJavascript("javascript:appLogin()", new ValueCallback<String>() {
    @Override
    public void onReceiveValue(String value) {
               LoginBean loginBean =  MyApplicaytion,getInstance,gson.fromJson(value,LoginBean.class);
              //这个地方处理返回值
        }
   });

}

加载本地html调用本地方法就不在介绍,网上很多!

3.JS调用本地方法
通过WebView的addJavascriptInterface()进行对象映射

1.定义一个与JS对象有映射关系的Android类:AndroidtoJs
 public class AndroidtoJs extends Object {
        // 定义JS需要调用的方法
        // 被JS调用的方法必须加入@JavascriptInterface注解
        @JavascriptInterface
        public void login() {
            //此方法就直接跳转到 购买成功的界面,同时还有另外一个方法判断是否需要关闭当前的界面
            if (!Application.iwxapi.isWXAppInstalled()) {
                Toast.makeText(MainActivity.this, "请先安装微信", Toast.LENGTH_SHORT).show();
            } else {
                final SendAuth.Req req = new SendAuth.Req();
                req.scope = "snsapi_userinfo";
                req.state = "wechat_sdk_demo_test";
                Application.iwxapi.sendReq(req);
            }
        }

        @JavascriptInterface
        public String toString() {
            return "androids";    //JS端通过该参数调用方法
        }
    }

加载本地js方法, html文件放在assets下

  mWebView.loadUrl("file:///android_asset/htmls_two.html");
  way =  "javascript:wxjswap"+"('"+url+"')";

JS端代码

 function 方法名(){
        // 由于对象映射,所以调用test对象等于调用Android映射的对象
            androids.login();
        //注意此处定义的Androids和移动端定义的要一样
         }

上诉交互方是仅仅是在项目中使用到的!更多方式参考这篇文章
https://www.jianshu.com/p/345f4d8a5cfa

三 webciew广告拦截
webview加载界面的时候会出现很多小广告,有运营商的也有一些乱七八糟的!最简单最暴力的方式就是只要不是我们项目域
名下的统统拦截!
具体方式如下:
首先定义一个数组

 <string-array name="legal_domain">
     <item>skin.se.360.cn</item>
     <item>m.gooooal.com</item>
 
 </string-array>
  把项目更中用到的所有域名全部写上去!是全部包括图片啥的,如果有一个用到的域名没有写上去可能会导致界面加载不出
  来,也可以在通过查看加载的所有域名来看有没有被漏掉的!

  拦截工具类
public class ADFilterTool {
   /**
    * 正则表达式
    */
   private static String PATTERN = " ";

   static {
       initPattern();
   }

   /**
    * 初始化pattern
    */
   private static void initPattern() {
       PATTERN = getPatternStr();
   }

   /**
    * 判断url的域名是否合法
    * <p>
    * 域名是否合法:自己项目中使用的域名,为合法域名;其它域名皆为不合法域名,进行屏蔽
    *
    * @param url
    * @return
    */
   public static boolean hasNotAd(String url) {
       if (TextUtils.isEmpty(url)) {
           LogUtils.e("拦截判断里面获取到的是空的");
           return false;
       }
       if (TextUtils.isEmpty(PATTERN)) {
           initPattern();
       }
       if (Pattern.matches(PATTERN, url)) {
  
           return true;
       }
       return false;
   }

   /**
    * 拼接正则表达式
    *
    * @return
    */
   private static String getPatternStr() {
       String[] adUrls = Application.getInstance().getResources().getStringArray(R.array.legal_domain);
       if (null != adUrls && adUrls.length > 0) {
           StringBuffer sb = new StringBuffer("^(https|http)://.*(");
           for (String a : adUrls) {
               if (null != a && a.length() > 0) {
                   sb.append(a).append("|");
               }
           }
           return sb.substring(0, sb.length() - 1) + ").*";
       }
       return null;
   }
}

hasNotAd方法里面可以看到所有加载的域名,当然也可以通过webview的shouldInterceptRequest()方法

具体使用在webview的shouldInterceptRequest方法调用

 @Override
            public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
                if (ADFilterTool.hasNotAd(url)) {
                return super.shouldInterceptRequest(view, url);
                } else {
                    return new WebResourceResponse(null, null, null);
                }
            }

上诉方法完美的解决了项目当中的广告页面!

四:webview重定向,以及地址中包含alipay,weixin等敏感字段时无法加载界面的处理方法!
我自己的项目中有些直接出现了alipays,weixin 有些则是alipayqr等相关字眼,加载的地址中包含这些字段时Webview就会无
法加载!,解决方案就是通过重定向到浏览器当中去打开这些界面!

   @Override
                public boolean shouldOverrideUrlLoading(WebView view, String url) {
                    LogUtils.e("跳转链接:" + url);
                    String newUrl = "";
                    if (url.contains("alipayqr")){
                        newUrl = url.replace("alipayqr", "alipays");
                    }

                    LogUtils.e("修改后的跳转链接" + newUrl);
                    if(newUrl.startsWith("alipays://")|| url.contains("weixin://") ){
                        Intent intent = new Intent();
                        intent.setAction(Intent.ACTION_VIEW);
                        if (url.contains("weixin://")){
                            intent.setData(Uri.parse(url));
                        }else {
                            intent.setData(Uri.parse(newUrl));
                        }
                        try {
                            startActivity(intent);
                        }catch (Exception e){
                            ToasUtils.showToast("充值失败,请联系客服");
                        }

                        return true;
                    }
                    return super.shouldOverrideUrlLoading(view, url);
            }

五。webview自定义报错界面
加载页面出错的时候webview原生报错很丑,有些情况下还会出现域名当这些信息我们不想直接向客户展示的时候就需要自
定义报错界面!

    onReceivedError();通过这个方法来进行处理
           @TargetApi(Build.VERSION_CODES.M)
           @Override
           public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
               view.removeAllViews();
               Log.e("log","报错拉");
               rlError.setVisibility(View.VISIBLE);   //自定义的报错界面
               view.loadUrl("about:blank");
           }
         



           @Override
           public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
               if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                   return;
               }
               Log.e("log","报错拉");
               rlError.setVisibility(View.VISIBLE);
               view.removeAllViews();
               view.loadUrl("about:blank");
           }

注意如果不加上view.loadUrl("about:blank");这行代码的话,webview的原生报错界面很多情况下还是会一闪而过!

六。 webview如何上传图片
项目中的客服使用的是H5界面,这里就需要向WEBVIEW上传图片,中途遇见过上传图片过大会不显示,也遇到过上传第一张图片没问题,上传第二张图片的时候就无法成功始终是空白!

 直接上究极方案,直接拿去这坨代码
  settings.setUseWideViewPort(true);
        settings.setLoadWithOverviewMode(true);
        settings.setJavaScriptEnabled(true);
        web.setWebChromeClient(new WebChromeClient() {

            // For Android < 3.0
            public void openFileChooser(ValueCallback<Uri> valueCallback) {
                uploadMessage = valueCallback;
                openImageChooserActivity();
            }

            // For Android  >= 3.0
            public void openFileChooser(ValueCallback valueCallback, String acceptType) {
                uploadMessage = valueCallback;
                openImageChooserActivity();
            }

            //For Android  >= 4.1
            public void openFileChooser(ValueCallback<Uri> valueCallback, String acceptType, String capture) {
                uploadMessage = valueCallback;
                openImageChooserActivity();
            }

            // For Android >= 5.0
            @Override
            public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, WebChromeClient.FileChooserParams fileChooserParams) {
                uploadMessageAboveL = filePathCallback;
                openImageChooserActivity();
                return true;
            }
        });


        web.setWebViewClient(new WebViewClient() {
            @Override
            public boolean shouldOverrideUrlLoading(WebView view, String url) {
                view.loadUrl(url);
                return true;
            }

            @Override
            public void onPageFinished(WebView view, String url) {
                web.loadUrl(lodurl);
            }
        });
    }
    private void openImageChooserActivity() {
        Intent i = new Intent(Intent.ACTION_GET_CONTENT);
        i.addCategory(Intent.CATEGORY_OPENABLE);
        i.setType("image/*");
        startActivityForResult(Intent.createChooser(i, "Image Chooser"), FILE_CHOOSER_RESULT_CODE);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == FILE_CHOOSER_RESULT_CODE) {
            if (null == uploadMessage && null == uploadMessageAboveL){
                return;
            }
            Uri result = data == null || resultCode != RESULT_OK ? null : data.getData();
            if (uploadMessageAboveL != null) {
                onActivityResultAboveL(requestCode, resultCode, data);
            } else if (uploadMessage != null) {
                uploadMessage.onReceiveValue(result);
                uploadMessage = null;
            }
        }
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    private void onActivityResultAboveL(int requestCode, int resultCode, Intent intent) {
        if (requestCode != FILE_CHOOSER_RESULT_CODE || uploadMessageAboveL == null){
            return;
        }
        Uri[] results = null;
        if (resultCode == Activity.RESULT_OK) {
            if (intent != null) {
                String dataString = intent.getDataString();
                ClipData clipData = intent.getClipData();
                if (clipData != null) {
                    results = new Uri[clipData.getItemCount()];
                    for (int i = 0; i < clipData.getItemCount(); i++) {
                        ClipData.Item item = clipData.getItemAt(i);
                        results[i] = item.getUri();
                    }
                }
                if (dataString != null){
                    results = new Uri[]{Uri.parse(dataString)};
                }
            }
        }
        uploadMessageAboveL.onReceiveValue(results);
        uploadMessageAboveL = null;
    }
  1. HTTPS地址当中的动态界面无法加载
    项目中加载的H5页面是HTTPS的,只能加载出静态界面,动态界面无法加载,根本原因就在于在安卓5.0以上,如果加载的地址是https,但是连接里面的内容,比如图片是http请求的那么就会导致图片无法加载!
    如下图就是非正常状态下的!, 一直显示加载中,动态加载界面无法显示!
image.png

加上代码,就可以解决问题

if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT){
getSettings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
}

相关知识:
问题相关知识分析:
从Android5.0以后,当一个安全的站点(https)去加载一个非安全的站点(http)时,需要配置Webview加载内容的混合模式,一共有如下三种模式:
MIXED_CONTENT_NEVER_ALLOW:Webview不允许一个安全的站点(https)去加载非安全的站点内容(http),比如,https网页内容的图片是http链接。强烈建议App使用这种模式,因为这样更安全。
MIXED_CONTENT_ALWAYS_ALLOW:在这种模式下,WebView是可以在一个安全的站点(Https)里加载非安全的站点内容(Http),这是WebView最不安全的操作模式,尽可能地不要使用这种模式。
MIXED_CONTENT_COMPATIBILITY_MODE:在这种模式下,当涉及到混合式内容时,WebView会尝试去兼容最新Web浏览器的风格。一些不安全的内容(Http)能被加载到一个安全的站点上(Https),而其他类型的内容将会被阻塞。这些内容的类型是被允许加载还是被阻塞可能会随着版本的不同而改变,并没有明确的定义。这种模式主要用于在App里面不能控制内容的渲染,但是又希望在一个安全的环境下运行。
分析:

在Android5.0以下,默认是采用的MIXED_CONTENT_ALWAYS_ALLOW模式,即总是允许WebView同时加载Https和Http;而从Android5.0开始,默认用MIXED_CONTENT_NEVER_ALLOW模式,即总是不允许WebView同时加载Https和Http。

参考博客:
原文:https://blog.csdn.net/beibaokongming/article/details/78832765

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

推荐阅读更多精彩内容

  • 链接:https://www.jianshu.com/p/fd61e8f4049e 一、简介 这部分主要介绍下 W...
    柒黍阅读 1,779评论 0 4
  • 这些都是曾经收集到的一些关于Webview的知识,有些工作中用到了,有些暂时还没有用到,这次统一整理下,希望对自己...
    乆丩乣阅读 11,908评论 14 101
  • webview基于WebKit引擎加载本地 和网络网页 loadUrl能调用js 函数,js也可以调用java对象...
    wilson93阅读 959评论 0 0
  • 知识点 webView设置 WebViewClient与WebChromeClient的区别 js调用java 应...
    张年轮阅读 437评论 0 1
  • 《你还在我身旁》瀑布的水逆流而上蒲公英种子从远处飘回,聚成伞的模样太阳从西边升起,落向东方子弹退回枪膛运动员回到起...
    紫苏种花生阅读 352评论 0 0