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

既然用到了第三方H5新闻及小游戏,肯定需要用到webview,这里仅做了一些基本处理;另外用到的是第三方的网页,需要去掉一些广告或第三方标志等,这就需要一套广告过滤的机制。
WebView
WebView做了一些基本设置,标题修改、返回及退出、页面加载控制、加载进度等...
WebSettings
这一块不多说,每个参数什么意思网上都很详细
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
<span class="hljs-meta">@SuppressLint</span>(<span class="hljs-string">"SetJavaScriptEnabled"</span>) <span class="hljs-meta">@SuppressWarnings</span>(<span class="hljs-string">"deprecation"</span>) <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">initWebView</span><span class="hljs-params">()</span> </span>{ mWebView.setInitialScale(<span class="hljs-number">80</span>); mWebView.setScrollbarFadingEnabled(<span class="hljs-keyword">true</span>); mWebView.setWebViewClient(<span class="hljs-keyword">new</span> ReWebViewClient()); mWebView.setWebChromeClient(<span class="hljs-keyword">new</span> ReWebChomeClient(<span class="hljs-keyword">this</span>, mProgressDialog)); mWebView.getSettings().setDefaultTextEncodingName(<span class="hljs-string">"UTF-8"</span>); WebSettings settings = mWebView.getSettings(); <span class="hljs-comment">// settings.setLayoutAlgorithm(LayoutAlgorithm.NARROW_COLUMNS);</span> settings.setBuiltInZoomControls(<span class="hljs-keyword">false</span>); settings.setSupportZoom(<span class="hljs-keyword">false</span>); <span class="hljs-keyword">int</span> screenDensity = getResources().getDisplayMetrics().densityDpi; WebSettings.ZoomDensity zoomDensity = WebSettings.ZoomDensity.MEDIUM; <span class="hljs-keyword">switch</span> (screenDensity) { <span class="hljs-keyword">case</span> DisplayMetrics.DENSITY_LOW: zoomDensity = WebSettings.ZoomDensity.CLOSE; <span class="hljs-keyword">break</span>; <span class="hljs-keyword">case</span> DisplayMetrics.DENSITY_MEDIUM: zoomDensity = WebSettings.ZoomDensity.MEDIUM; <span class="hljs-keyword">break</span>; <span class="hljs-keyword">case</span> DisplayMetrics.DENSITY_HIGH: zoomDensity = WebSettings.ZoomDensity.FAR; <span class="hljs-keyword">break</span>; } settings.setDefaultZoom(zoomDensity); settings.setRenderPriority(RenderPriority.HIGH); settings.setUseWideViewPort(<span class="hljs-keyword">true</span>); settings.setLoadWithOverviewMode(<span class="hljs-keyword">true</span>); settings.setJavaScriptEnabled(<span class="hljs-keyword">true</span>); settings.setAllowFileAccess(<span class="hljs-keyword">true</span>);<span class="hljs-comment">// 设置允许访问文件数据</span> settings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK); settings.setJavaScriptCanOpenWindowsAutomatically(<span class="hljs-keyword">true</span>); settings.setLoadsImagesAutomatically(<span class="hljs-keyword">true</span>); settings.setDomStorageEnabled(<span class="hljs-keyword">true</span>); settings.setDatabaseEnabled(<span class="hljs-keyword">true</span>); fixDirPath(); settings.setBlockNetworkImage(<span class="hljs-keyword">false</span>);<span class="hljs-comment">//解决图片不显示</span> <span class="hljs-keyword">if</span>(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { settings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW); } } |
文件选择
定义了一个文件选择回调接口
1 2 3 4 5 6 |
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">OpenFileChooserCallBack</span> </span>{ <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">openFileChooserCallBack</span><span class="hljs-params">(ValueCallback<Uri> uploadMsg, String acceptType)</span></span>; <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">openFileChooserImplForAndroid5</span><span class="hljs-params">(ValueCallback<Uri[]> uploadMsg)</span></span>; } |
在ReWebChomeClient中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
<span class="hljs-keyword">private</span> OpenFileChooserCallBack mOpenFileChooserCallBack; <span class="hljs-keyword">private</span> ProgressDialogEx mProgressDialog; <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">ReWebChomeClient</span><span class="hljs-params">(OpenFileChooserCallBack openFileChooserCallBack, ProgressDialogEx progressDialog)</span> </span>{ mOpenFileChooserCallBack = openFileChooserCallBack; mProgressDialog = progressDialog; } <span class="hljs-comment">// For Android 3.0+</span> <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">openFileChooser</span><span class="hljs-params">(ValueCallback<Uri> uploadMsg, String acceptType)</span> </span>{ mOpenFileChooserCallBack.openFileChooserCallBack(uploadMsg, acceptType); } <span class="hljs-comment">// For Android < 3.0</span> <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">openFileChooser</span><span class="hljs-params">(ValueCallback<Uri> uploadMsg)</span> </span>{ openFileChooser(uploadMsg, <span class="hljs-string">""</span>); } <span class="hljs-comment">// For Android > 4.1.1</span> <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">openFileChooser</span><span class="hljs-params">(ValueCallback<Uri> uploadMsg, String acceptType, String capture)</span> </span>{ openFileChooser(uploadMsg, acceptType); } <span class="hljs-comment">// For Android > 5.0</span> <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">boolean</span> <span class="hljs-title">onShowFileChooser</span> <span class="hljs-params">(WebView webView, ValueCallback<Uri[]> uploadMsg, WebChromeClient.FileChooserParams fileChooserParams)</span> </span>{ mOpenFileChooserCallBack.openFileChooserImplForAndroid5(uploadMsg); <span class="hljs-keyword">return</span> <span class="hljs-keyword">true</span>; } |
加载进度
加载进度显示,这里采用动画TranslateAnimation
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AnimaUtils</span> </span>{ <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">startImageViewAnima</span><span class="hljs-params">(ImageView loading)</span> </span>{ TranslateAnimation animation = <span class="hljs-keyword">new</span> TranslateAnimation(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">120</span>); animation.setDuration(<span class="hljs-number">500</span>); animation.setRepeatMode(Animation.REVERSE); animation.setRepeatCount(Integer.MAX_VALUE); loading.startAnimation(animation); } <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">removeImageViewAnima</span><span class="hljs-params">(ImageView loading)</span> </span>{ loading.setAnimation(<span class="hljs-keyword">null</span>); } } |
进入网页时
1 2 |
<span class="hljs-selector-tag">AnimaUtils</span><span class="hljs-selector-class">.startImageViewAnima</span>(<span class="hljs-selector-tag">loadingIv</span>); |
在ReWebViewClient中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<span class="hljs-meta">@Override</span> <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onProgressChanged</span><span class="hljs-params">(WebView view, <span class="hljs-keyword">int</span> newProgress)</span> </span>{ <span class="hljs-keyword">if</span>(newProgress >= <span class="hljs-number">100</span>) { AnimaUtils.removeImageViewAnima(); } <span class="hljs-keyword">super</span>.onProgressChanged(view, newProgress); } <span class="hljs-meta">@Override</span> <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onReceivedTitle</span><span class="hljs-params">(WebView view, String title)</span> </span>{ AnimaUtils.removeImageViewAnima(); <span class="hljs-keyword">super</span>.onReceivedTitle(view, title); } |
onBackPressed
写得有点繁琐,大体逻辑是:点击返回时,显示顶部退出按钮(为了解决反复301重定向导致退不出);然后通过canGoBack判断是返回goBack还是退出finish,如果是goBack,则将标题修改为上一页的标题。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
<span class="hljs-meta">@Override</span> <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onBackPressed</span><span class="hljs-params">()</span> </span>{ <span class="hljs-keyword">if</span>(closeView != <span class="hljs-keyword">null</span>) { closeView.setVisibility(View.VISIBLE); } <span class="hljs-keyword">else</span> { finishAct(); <span class="hljs-keyword">return</span>; } <span class="hljs-keyword">if</span> (mWebView.canGoBack()) { mWebView.goBack(); <span class="hljs-keyword">try</span> { setTitleTv(mWebView.copyBackForwardList().getCurrentItem().getTitle()); } <span class="hljs-keyword">catch</span> (Exception e) { <span class="hljs-keyword">new</span> Handler().postDelayed(<span class="hljs-keyword">new</span> Runnable() { <span class="hljs-meta">@Override</span> <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">run</span><span class="hljs-params">()</span> </span>{ <span class="hljs-keyword">try</span> { setTitleTv(mWebView.getTitle()); } <span class="hljs-keyword">catch</span> (Exception e2) { e2.printStackTrace(); } } }, <span class="hljs-number">500</span>); } <span class="hljs-keyword">return</span>; } finishAct(); } |
广告过滤
广告过滤是比较繁琐的一块,做过几个版本,但是都不是很彻底,在机型兼容性和版本兼容性上不太好。大体还是围绕两个方向来展开,shouldInterceptRequest拦截和页面加载完毕后的js移除。
这两种方法都是在ReWebViewClient中进行操作:
shouldInterceptRequest拦截
通过shouldInterceptRequest方法拦截指定页面及资源,这里5.0前后用到的不同
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
<span class="hljs-meta">@SuppressLint</span>(<span class="hljs-string">"DefaultLocale"</span>) <span class="hljs-meta">@Override</span> <span class="hljs-function"><span class="hljs-keyword">public</span> WebResourceResponse <span class="hljs-title">shouldInterceptRequest</span><span class="hljs-params">(WebView view, String url)</span> </span>{ <span class="hljs-keyword">try</span> { <span class="hljs-keyword">if</span> (ADFilterUtil.hasAd(view.getContext(), url) || ADFilterUtil.isAd(view.getContext(), url.toLowerCase())) { <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> WebResourceResponse(<span class="hljs-keyword">null</span>,<span class="hljs-keyword">null</span>,<span class="hljs-keyword">null</span>); } } <span class="hljs-keyword">catch</span> (Exception e) { e.printStackTrace(); } <span class="hljs-keyword">return</span> <span class="hljs-keyword">super</span>.shouldInterceptRequest(view, url); } <span class="hljs-meta">@RequiresApi</span>(api = Build.VERSION_CODES.LOLLIPOP) <span class="hljs-meta">@Override</span> <span class="hljs-function"><span class="hljs-keyword">public</span> WebResourceResponse <span class="hljs-title">shouldInterceptRequest</span><span class="hljs-params">(WebView view, WebResourceRequest request)</span> </span>{ <span class="hljs-keyword">try</span> { String url = request.getUrl().getHost().toLowerCase() + request.getUrl().getPath().toLowerCase(); <span class="hljs-keyword">if</span> (ADFilterUtil.hasAd(view.getContext(), url) || ADFilterUtil.isAd(view.getContext(), url)) { <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> WebResourceResponse(<span class="hljs-keyword">null</span>,<span class="hljs-keyword">null</span>,<span class="hljs-keyword">null</span>); } } <span class="hljs-keyword">catch</span> (Exception e) { e.printStackTrace(); } <span class="hljs-keyword">return</span> <span class="hljs-keyword">super</span>.shouldInterceptRequest(view, request); } |
上面用到的isAd和hasAd中对拦截列表中的url或者关键字进行拦截
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> boolean <span class="hljs-title">hasAd</span><span class="hljs-params">(Context context, String url)</span> </span>{ Resources res = context.getResources(); String[] adUrls = res.getStringArray(R.<span class="hljs-built_in">array</span>.adBlockUrl); <span class="hljs-keyword">for</span> (String adUrl : adUrls) { <span class="hljs-keyword">if</span> (url.contains(adUrl)) { <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>; } } <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>; } <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> boolean <span class="hljs-title">isAd</span><span class="hljs-params">(Context context, String url)</span> </span>{ Resources res = context.getResources(); String[] adUrls = res.getStringArray(R.<span class="hljs-built_in">array</span>.adUrl); <span class="hljs-keyword">for</span> (String adUrl : adUrls) { <span class="hljs-keyword">if</span> (url.equals(adUrl)) { <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>; } } <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>; } |
onPageFinished中通过js移除
这里因为app中都是用到的同一个站点的内容,所以分析其网页,移除指定的模块
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
<span class="hljs-comment">// Override</span> <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onPageFinished</span><span class="hljs-params">(WebView view, String url)</span> </span>{ super.onPageFinished(view, url); view.loadUrl(ADFilterUtil.getClearAdDivJs(E7App.mApp)); } <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> String <span class="hljs-title">getClearAdDivJs</span><span class="hljs-params">(Context context)</span> </span>{ String js = <span class="hljs-string">"javascript:"</span>; Resources res = context.getResources(); String[] adDivs = res.getStringArray(R.<span class="hljs-built_in">array</span>.adBlockDiv); <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i < adDivs.length; i++) { js += <span class="hljs-string">"var adDiv"</span> + i + <span class="hljs-string">"= document.getElementById('news_check').getElementById('"</span> + adDivs[i] + <span class="hljs-string">"');"</span> + <span class="hljs-string">"if(adDiv"</span> + i + <span class="hljs-string">" != null)"</span> + <span class="hljs-string">"adDiv"</span> + i + <span class="hljs-string">".parentNode.removeChild(adDiv"</span> + i + <span class="hljs-string">");"</span>; } String[] adDivsC = res.getStringArray(R.<span class="hljs-built_in">array</span>.adBlockDivClass); <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i < adDivsC.length; i++) { js += <span class="hljs-string">"var adDivsC"</span> + i + <span class="hljs-string">"= document.getElementsByClassName('"</span> + adDivsC[i] + <span class="hljs-string">"');"</span> + <span class="hljs-string">"if(adDivsC"</span> + i + <span class="hljs-string">" != null)"</span> + <span class="hljs-string">"adDivsC"</span> + i + <span class="hljs-string">".parentNode.removeChild(adDivsC"</span> + i + <span class="hljs-string">");"</span>; } String[] adSections = res.getStringArray(R.<span class="hljs-built_in">array</span>.adBlockSectionClass); <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i < adSections.length; i++) { js += <span class="hljs-string">"var adSection"</span> + i + <span class="hljs-string">"= document.getElementById('news_check').getElementById('J_hot_news').getElementsByClassName('"</span> + adSections[i] + <span class="hljs-string">"');"</span> + <span class="hljs-string">"if(adSection"</span> + i + <span class="hljs-string">" != null)"</span> + <span class="hljs-string">"adSection"</span> + i + <span class="hljs-string">".parentNode.removeChild(adSection"</span> + i + <span class="hljs-string">");"</span>; } <span class="hljs-keyword">return</span> js; } |
简书:ThinkinLiu 博客: IT老五
以上就是【小萌伴】App中关于新闻/H5游戏模块及广告过滤的主体内容,具体的可以参考项目中com.e7yoo.e7.app.news中的内容。
相关内容:
1. 思量再三,终于鼓起勇气开源~
2.【小萌伴】机器人陪聊模块分享
3.【小萌伴】新闻/H5游戏模块及广告过滤