美文网首页Android开发经验谈开发者日记Android开发
3.【小萌伴】新闻/H5游戏模块及广告过滤

3.【小萌伴】新闻/H5游戏模块及广告过滤

作者: IT老五 | 来源:发表于2019-03-19 13:50 被阅读6次

    在完成主体聊天机器人功能后,拓展了新闻资讯及小游戏模块。精力有限,新闻列表用原生,具体内容则用h5嵌入第三方站点,而游戏则分为两部分,有几个原生小游戏(2048、防御小鸟、打飞机、贪吃蛇),更多的是爬了4399的h5小游戏。

    xmb.itlao5.com

    既然用到了第三方H5新闻及小游戏,肯定需要用到webview,这里仅做了一些基本处理;另外用到的是第三方的网页,需要去掉一些广告或第三方标志等,这就需要一套广告过滤的机制。

    WebView

    WebView做了一些基本设置,标题修改、返回及退出、页面加载控制、加载进度等...

    WebSettings

    这一块不多说,每个参数什么意思网上都很详细

        @SuppressLint("SetJavaScriptEnabled")
        @SuppressWarnings("deprecation")
        public void initWebView() {
            mWebView.setInitialScale(80);
            mWebView.setScrollbarFadingEnabled(true);
            mWebView.setWebViewClient(new ReWebViewClient());
            mWebView.setWebChromeClient(new ReWebChomeClient(this, mProgressDialog));
            mWebView.getSettings().setDefaultTextEncodingName("UTF-8");
            WebSettings settings = mWebView.getSettings();
            // settings.setLayoutAlgorithm(LayoutAlgorithm.NARROW_COLUMNS);
            settings.setBuiltInZoomControls(false);
            settings.setSupportZoom(false);
            int screenDensity = getResources().getDisplayMetrics().densityDpi;
            WebSettings.ZoomDensity zoomDensity = WebSettings.ZoomDensity.MEDIUM;
            switch (screenDensity) {
            case DisplayMetrics.DENSITY_LOW:
                zoomDensity = WebSettings.ZoomDensity.CLOSE;
                break;
            case DisplayMetrics.DENSITY_MEDIUM:
                zoomDensity = WebSettings.ZoomDensity.MEDIUM;
                break;
            case DisplayMetrics.DENSITY_HIGH:
                zoomDensity = WebSettings.ZoomDensity.FAR;
                break;
            }
            settings.setDefaultZoom(zoomDensity);
            settings.setRenderPriority(RenderPriority.HIGH);
            settings.setUseWideViewPort(true);
            settings.setLoadWithOverviewMode(true);
            settings.setJavaScriptEnabled(true);
            settings.setAllowFileAccess(true);// 设置允许访问文件数据
            settings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
            settings.setJavaScriptCanOpenWindowsAutomatically(true);
            settings.setLoadsImagesAutomatically(true);
    
            settings.setDomStorageEnabled(true);
            settings.setDatabaseEnabled(true);
    
            fixDirPath();
            settings.setBlockNetworkImage(false);//解决图片不显示
            if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                settings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
            }
        }
    
    
    文件选择

    定义了一个文件选择回调接口

        public interface OpenFileChooserCallBack {
            void openFileChooserCallBack(ValueCallback<Uri> uploadMsg,
                                         String acceptType);
            void openFileChooserImplForAndroid5(ValueCallback<Uri[]> uploadMsg);
        }
    

    在ReWebChomeClient中

        private OpenFileChooserCallBack mOpenFileChooserCallBack;
        private ProgressDialogEx mProgressDialog;
    
        public ReWebChomeClient(OpenFileChooserCallBack openFileChooserCallBack, ProgressDialogEx progressDialog) {
            mOpenFileChooserCallBack = openFileChooserCallBack;
            mProgressDialog = progressDialog;
        }
    
        // For Android 3.0+
        public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType) {
            mOpenFileChooserCallBack.openFileChooserCallBack(uploadMsg, acceptType);
        }
    
        // For Android < 3.0
        public void openFileChooser(ValueCallback<Uri> uploadMsg) {
            openFileChooser(uploadMsg, "");
        }
    
        // For Android > 4.1.1
        public void openFileChooser(ValueCallback<Uri> uploadMsg,
                                    String acceptType, String capture) {
            openFileChooser(uploadMsg, acceptType);
        }
    
         // For Android > 5.0
         public boolean onShowFileChooser (WebView webView, ValueCallback<Uri[]>
             uploadMsg, WebChromeClient.FileChooserParams fileChooserParams) {
             mOpenFileChooserCallBack.openFileChooserImplForAndroid5(uploadMsg);
             return true;
         }
    
    加载进度

    加载进度显示,这里采用动画TranslateAnimation

    public class AnimaUtils {
    
        public static void startImageViewAnima(ImageView loading) {
            TranslateAnimation animation = new TranslateAnimation(0, 0, 0, 120); 
            animation.setDuration(500);
            animation.setRepeatMode(Animation.REVERSE);
            animation.setRepeatCount(Integer.MAX_VALUE);
            loading.startAnimation(animation);
        }
        
        public static void removeImageViewAnima(ImageView loading) {
            loading.setAnimation(null);
        }
    }
    

    进入网页时

        AnimaUtils.startImageViewAnima(loadingIv);
    

    在ReWebViewClient中

        @Override
        public void onProgressChanged(WebView view, int newProgress) {
            if(newProgress >= 100) {
                AnimaUtils.removeImageViewAnima();
            }
            super.onProgressChanged(view, newProgress);
        }
        
        @Override
        public void onReceivedTitle(WebView view, String title) {
            AnimaUtils.removeImageViewAnima();
            super.onReceivedTitle(view, title);
        }
    
    onBackPressed

    写得有点繁琐,大体逻辑是:点击返回时,显示顶部退出按钮(为了解决反复301重定向导致退不出);然后通过canGoBack判断是返回goBack还是退出finish,如果是goBack,则将标题修改为上一页的标题。

        @Override
        public void onBackPressed() {
            if(closeView != null) { 
                closeView.setVisibility(View.VISIBLE);
            } else {
                finishAct();
                return;
            }
            if (mWebView.canGoBack()) {
                mWebView.goBack();
                try {
                    setTitleTv(mWebView.copyBackForwardList().getCurrentItem().getTitle());
                } catch (Exception e) {
                    new Handler().postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                setTitleTv(mWebView.getTitle());
                            } catch (Exception e2) {
                                e2.printStackTrace();
                            }
                        }
                    }, 500);
                }
                return;
            }
            finishAct();
        }
    

    广告过滤

    广告过滤是比较繁琐的一块,做过几个版本,但是都不是很彻底,在机型兼容性和版本兼容性上不太好。大体还是围绕两个方向来展开,shouldInterceptRequest拦截和页面加载完毕后的js移除

    这两种方法都是在ReWebViewClient中进行操作:

    shouldInterceptRequest拦截

    通过shouldInterceptRequest方法拦截指定页面及资源,这里5.0前后用到的不同

        @SuppressLint("DefaultLocale")
        @Override
        public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
            try {
                if (ADFilterUtil.hasAd(view.getContext(), url) || ADFilterUtil.isAd(view.getContext(), url.toLowerCase())) {
                    return new WebResourceResponse(null,null,null);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            return super.shouldInterceptRequest(view, url);
        }
    
        @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
        @Override
        public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
            try {
                String url = request.getUrl().getHost().toLowerCase() +  request.getUrl().getPath().toLowerCase();
                if (ADFilterUtil.hasAd(view.getContext(), url) || ADFilterUtil.isAd(view.getContext(), url)) {
                    return new WebResourceResponse(null,null,null);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            return super.shouldInterceptRequest(view, request);
        }
    

    上面用到的isAd和hasAd中对拦截列表中的url或者关键字进行拦截

        public static boolean hasAd(Context context, String url) {
            Resources res = context.getResources();
            String[] adUrls = res.getStringArray(R.array.adBlockUrl);
            for (String adUrl : adUrls) {
                if (url.contains(adUrl)) {
                    return true;
                }
            }
            return false;
        }
    
        public static boolean isAd(Context context, String url) {
            Resources res = context.getResources();
            String[] adUrls = res.getStringArray(R.array.adUrl);
            for (String adUrl : adUrls) {
                if (url.equals(adUrl)) {
                    return true;
                }
            }
            return false;
        }
    
    onPageFinished中通过js移除

    这里因为app中都是用到的同一个站点的内容,所以分析其网页,移除指定的模块

        // Override
        public void onPageFinished(WebView view, String url) {
            super.onPageFinished(view, url);
            view.loadUrl(ADFilterUtil.getClearAdDivJs(E7App.mApp));
        }
    
        public static String getClearAdDivJs(Context context) {
            String js = "javascript:";
            Resources res = context.getResources();
            String[] adDivs = res.getStringArray(R.array.adBlockDiv);
            for (int i = 0; i < adDivs.length; i++) {
    
                js += "var adDiv" + i + "= document.getElementById('news_check').getElementById('" + adDivs[i] + "');" +
                        "if(adDiv" + i + " != null)" +
                        "adDiv" + i + ".parentNode.removeChild(adDiv" + i + ");";
            }
            String[] adDivsC = res.getStringArray(R.array.adBlockDivClass);
            for (int i = 0; i < adDivsC.length; i++) {
    
                js += "var adDivsC" + i + "= document.getElementsByClassName('" + adDivsC[i] + "');" +
                        "if(adDivsC" + i + " != null)" +
                        "adDivsC" + i + ".parentNode.removeChild(adDivsC" + i + ");";
            }
            String[] adSections = res.getStringArray(R.array.adBlockSectionClass);
            for (int i = 0; i < adSections.length; i++) {
    
                js += "var adSection" + i + "= document.getElementById('news_check').getElementById('J_hot_news').getElementsByClassName('" + adSections[i] + "');" +
                        "if(adSection" + i + " != null)" +
                        "adSection" + i + ".parentNode.removeChild(adSection" + i + ");";
            }
            return js;
        }
    

    简书:ThinkinLiu 博客: IT老五

    以上就是【小萌伴】App中关于新闻/H5游戏模块及广告过滤的主体内容,具体的可以参考项目中com.e7yoo.e7.app.news中的内容。

    相关内容:
    1. 思量再三,终于鼓起勇气开源~
    2.【小萌伴】机器人陪聊模块分享
    3.【小萌伴】新闻/H5游戏模块及广告过滤

    相关文章

      网友评论

        本文标题:3.【小萌伴】新闻/H5游戏模块及广告过滤

        本文链接:https://www.haomeiwen.com/subject/amfgmqtx.html