做另一面的自己

手机浏览器广告拦截实现及自动化测试

1 广告拦截产品需求

1.1 在页面加载过程中进行拦截(包括重新载入),做到不会让广告闪现后才被拦截

1.2 目前我们的拦截规则直接使用猎豹的规则list进行修改,通过JS注入和拦截请求的方式进行广告拦截,规则要求服务端可控,浏览器本地会存一份"广告拦截规则"。

1.3 广告拦截更新机制

规则文件名:libadblockrules(联盟广告通用);libadblockextrules(根据域名修改css样式); libadwhitedomainrules(白名单规则,运营需求有些网页不拦截广告)

规则更新时机:浏览器启动后,检测更新"广告拦截规则";

规则更新逻辑:规则在浏览器本地有个时间戳,向服务post本地规则的时间戳进行比对,当服务器规则的时间戳新于本地的则下载新的规则进行更新,反之则不进行更新;

新规则应用时机(何时在本地起效):更新完成规则后,下次启动浏览器时应用。

拦截提示:设置界面有提示模块

2 广告拦截实现

2.1 广告拦截中文社区

2.2 ABP官方: https://adblockplus.org/en/source 这里可以下载ABP官方源码(开源组织一直在维护)

2.3 规则文件:
http://abpchina.org/forum/forum.php?mod=viewthread&tid=29667&extra=page%3D1

ABP for android 项目已开源,github地址: https://github.com/adblockplus/adblockplusandroid

2.4 ABP官方实现:

通过设置代理,拦载请求,广告请求地址与拦截规则进行匹配,匹配到规则成功就不发送请求,自然就不会加载到请求到客户端,这种拦截通用于整个手机的

2.5 手机浏览器广告拦截具体实现:

广告规则:应用首次启动,拷贝包里的默认规则到应用的data/data/package目录下,非首次启动直接读取本地规则,将其保存到缓存;同时向服务器请求拦截规则,成功请求下来保存文件,时间戳分别保存,请求在JsHandler类请求参数如下:
Requst params:

1
appname=androidbrowser;exrules_version=1473247972;channel=UMENG_CHANNEL_VALUE;whitelist_version=1473058756;abprules_version=

拦截时机:核心处理类在AdBlockApi

拦截有两种方式:

1).WebView加载的时候注入javascript修改网页css样式

在WebView的回调

1
onProgressChange()mAdblock.onProgressChanged(view);


1
onPageFinishedmAdblock.onPageFinished(view)

,两个回调中注入广告的js,主要是拦截一些banner广告和通用规则拦截导致的网页内部css样式错乱进行调整;其由通用js和规则文件js中拼接而成,具体可看代码实现。

2). shouldInterceptRequest拦载请求

Webview在加载的时候资源的每个请求以及js请求都会进行这个回调,客户端可以在这个回调中做拦截处理

1
mAdblock.shouldInterceptRequest(view, url, mCurrentState.mUrl)

原理是将请求中的8位一组分割,然后与缓存下来的通用规则列表通过正则来匹配,匹配成功则进行拦截,否则不拦截。匹配的效率跟资源url的长度也和正则匹配效率有关系,这也是广告拦截会影响网页加载速度的一个潜在风险。规则解析满足大部分官方提供的标准以便适用官方规则:

https://adblockplus.org/zh_CN/filters,自己添加通用规则也按照此文档。

这两种方式同时时行保证了页面在被拦载导致页面错乱的情况下可以进行调整;服务器端控制规则可以保证运营需求,合作客户不拦,页面拦截异常时加白名单控制等情况(白名单针对域名)。

3 广告拦截维护

两份默认规则文件都放在asset/js目录下,libadblockextrules根据官方的书写规则即可,libadblockextrules的写法与官方有差异。这里举个例子(以逗号分隔):一条规则只单行显示

1
.weibo.cn,1,1,ad_banner

第一位:要拦截的网站的域名

第二位:要拦截元素的tag,0表示class,1表示id

第三位:要执行拦截操作的事件action,1表示删除节点;3表示删除上一个节点;4表示下一个节点;5表示自定义事件,用于修改复杂css样式,js自己定义

第四位:元素节点的id名称或者class名称,或者当action为5时自己定义的js字符串

日常维护这两个规则文件即可,然后提交给测试服务器。

4 广告拦截自动化

为了提升运营批量定时检查广告的效率和准确度,很需要为广告拦截写一个自动化去发现广告,截图,方便运营查看。

  1. 集成开源android测试框架Robotium:

    1
    androidTestCompile 'com.jayway.android.robotium:robotium-solo:5.5.4'
  2. 在app androidTest包下声明一个类继承ActivityInstrumentationTestCase2

  3. 重写setup() tearDown等方法,通过Solo类来获取要测试的activity的view控件,模拟用户操作,操作其子控件,Robotium提供了官方api(下载即可),书写脚本,然后在手机上运行。