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

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

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

   static {
       initPattern();
   }

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

   /**
    * 判断url的域名是否合法
    * 

* 域名是否合法:自己项目中使用的域名,为合法域名;其它域名皆为不合法域名,进行屏蔽 * * @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 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 valueCallback, String acceptType, String capture) {
                uploadMessage = valueCallback;
                openImageChooserActivity();
            }

            // For Android >= 5.0
            @Override
            public boolean onShowFileChooser(WebView webView, ValueCallback 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请求的那么就会导致图片无法加载!
    如下图就是非正常状态下的!, 一直显示加载中,动态加载界面无法显示!
webview总结_第1张图片
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

你可能感兴趣的:(webview总结)