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 uploadMsg, String acceptType); void openFileChooserImplForAndroid5(ValueCallback 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 uploadMsg, String acceptType) { mOpenFileChooserCallBack.openFileChooserCallBack(uploadMsg, acceptType); } // For Android < 3.0 public void openFileChooser(ValueCallback uploadMsg) { openFileChooser(uploadMsg, ""); } // For Android > 4.1.1 public void openFileChooser(ValueCallback uploadMsg, String acceptType, String capture) { openFileChooser(uploadMsg, acceptType); } // For Android > 5.0 public boolean onShowFileChooser (WebView webView, ValueCallback 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.【小萌伴Android】思量再三,终于鼓起勇气开源~
2.【小萌伴Android】机器人陪聊模块分享
3.【小萌伴Android】新闻/H5游戏模块及广告过滤
更多相关文章
- android小游戏制作基础,View实现游戏布局和方法
- Android上如何让应用截获系统按键
- Android小游戏-数独(附源码)
- Android事件分发机制以及滑动冲突处理
- Android实现短信验证码自动拦截读取功能
- 关于Handler的拦截
- Android仿京东App购物车 二级列表+全选反选+Ok封装+拦截器+结算+
- Android中Touch事件分发过程全解析
- @功能 中用到 android EditText插入字符串到光标所在位置