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

在完成主体聊天机器人功能后,拓展了新闻资讯及小游戏模块。精力有限,新闻列表用原生,具体内容则用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;
    }

个人博客: IT老五
微信公众号:【IT老五(it-lao5)】,一起源创,一起学习!

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

相关内容:
【小萌伴Android】相关文章目录
1.【小萌伴Android】思量再三,终于鼓起勇气开源~
2.【小萌伴Android】机器人陪聊模块分享
3.【小萌伴Android】新闻/H5游戏模块及广告过滤
4.【小萌伴Android】段子趣图模块及其实现段子趣图数据爬取
5.【小萌伴Android】原生小游戏及其实现(一)2048

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 143,201评论 1 300
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 61,387评论 1 257
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 94,683评论 0 213
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 41,080评论 0 179
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 48,865评论 1 255
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 38,810评论 1 177
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 30,440评论 2 271
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 29,200评论 0 167
  • 想象着我的养父在大火中拼命挣扎,窒息,最后皮肤化为焦炭。我心中就已经是抑制不住地欢快,这就叫做以其人之道,还治其人...
    爱写小说的胖达阅读 29,019评论 6 231
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 32,540评论 0 213
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 29,337评论 2 215
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 30,658评论 1 231
  • 白月光回国,霸总把我这个替身辞退。还一脸阴沉的警告我。[不要出现在思思面前, 不然我有一百种方法让你生不如死。]我...
    爱写小说的胖达阅读 24,255评论 0 32
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 27,145评论 2 214
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 31,535评论 3 206
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,626评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,028评论 0 166
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 33,555评论 2 230
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 33,652评论 2 231

推荐阅读更多精彩内容