广告屏蔽:国内各电商 Web App 页面的 Native App 下载提示屏蔽

浏览国内各电商的 Web App 页面,总是会有下载它们 App 的提示,本来手机屏幕就小,加上该提示不易关闭,有些还会遮挡住页面部分内容。总之,体验不是很好!接下来就谈谈各电商的广告原理以及屏蔽方法。

首先从简单的下手好了,苏宁
苏宁的广告只出现在首页顶部,通过 Chrome 从首页的 HTML 文档中就能看到苏宁的处理,简单粗暴。

1
2
3
4
5
6
<!-- index -->
<!-- download -->
<div class="top-dload w pr">
<a href="javascript:void(0);" class="close" onclick="this.parentNode.style.display = 'none'"></a>
<a href="javascript:void(0);" class="click" onclick="downloadApp();"><img src="/RES/wapv2/images/top.png" alt=""></a>
</div>

自然屏蔽也非常简单了:

1
2
3
webView.loadUrl("javascript:"
+ "var ad = document.getElementsByClassName('top-dload')[0];"
+ "ad.style.display = 'none';");

以上是第一种广告处理的方式。

国美也简单,但处理上好过苏宁的。国美的广告只出现在首页顶部,也不会固定在页面的某块区域。
首先,通过 Chrome 查看首页结构,定位到这里:

1
2
3
4
5
6
<!-- index.html -->
<input type="hidden" value="_" id="float_id">
<aside class='supernatant' id='spt'>
<img src="http://img11.gomein.net.cn/image/prodimg/promotion_image/promoImg/201412/20141201/fuceng12.1.jpg">
<span class='sign' id='spt_close'></span>
</aside>

到这里已经拿到广告位元素的 ID 了,通过 DOM 编程就能将其隐藏或 remove 掉。但是这样有一点不好,由于只能等待其页面加载完成,才能植入 JS 代码。所以,每一次进入首页,都会先显示广告元素。为了寻求更好的解决方案,继续查看其 JS 代码。

1
2
3
4
5
6
7
8
// index.js
// 顶部浮层是否显示
var float_cookie_name=$('#float_id').val();
if(gomeBase.getCookie(float_cookie_name)){
if($id('spt')!=undefined){
$id('spt').style.display='none';
}
}

从以上代码可以看出,当存在以 ID 为 float_id 的 value 为 key 的 Cookie 时,广告位元素会被隐藏(也就不需要植入 JS 手动操作了)。继续看国美是怎么判断并 setCookie 的

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
// gome_base.js
setCookie: function(e, g, f) {
var h = new Date();
h.setTime(h.getTime() + f);
document.cookie = e + "=" + escape(g) + ";expires=" + h.toGMTString()
}
// ...
appDownloadIdxTop: function(f) {
var e = $id("spt_close"), g = $id("spt");
if (f == undefined) {
g.addEventListener(gomeBase.clicks, function(h) {
if (h.target != e) {
gomeBase.appStart()
}
}, false);
e.addEventListener(gomeBase.clicks, function() {
g.style.display = "none";
var h = $("#float_id").val();
gomeBase.setCookie(h, "1")
}, false)
} else {
g.addEventListener(gomeBase.clicks, function(h) {
if (f != undefined && h.target != e) {
d.location.href = f
}
}, false);
e.addEventListener(gomeBase.clicks, function() {
g.style.display = "none";
var h = $("#float_id").val();
gomeBase.setCookie(h, "1")
}, false)
}
}

所以,当点击广告元素上的关闭按钮时,会被写入 Cookie。这时,只需要设置 Cookie,模拟关闭广告操作即可。

代码如下:

1
2
3
4
5
6
webView.loadUrl("javascript:"
+ "var o = new Date;"
+ "o.setTime(o.getTime() + 10 * 86400 * 1e3);"
+ "document.cookie = '_' + '=' + escape(1) + ';expires=' + o.toGMTString();"
+ "var ad = document.getElementById('spt');"
+ "ad.style.display = 'none';");

只要设置的 Cookie 有效期长,且 WebView 的数据不被清理掉,广告元素就这样被屏蔽掉。

国美的提示比较简单,也没那么烦人。易迅同样是首页显示大广告,几乎占了手机屏幕的 2/3,不过其广告 24 小时内只显示一次(第一次显示之后就会写入 Cookie,有效期 24 小时)。原理就和国美一样,通过写 Cookie,找到易迅是如何写 Cookie的,再将其 Cookie 有效期延长,易迅的广告也就屏蔽了。

易迅广告相关代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!-- index -->
<!-- /三个快捷入口 -->
<div class="mod_download" style='display: none;'>
<div class="bd">
<div class="hd">
<img src="#" alt="下载易迅APP" width="306" height="241" class="appdownad_img_pos1_200081">
</div>
<a class="btn appdownad_title_pos3_200081 appdownad_url_pos3_200081" ytag="21001"></a>
<div class="links">
<a href="#" class="web J_close" id='closeAId' ytag="21002">浏览手机网页</a>
<a href="wap2app://app.launch/param?act=cps&type=home" class="app" id='openAppId' ytag="21004">打开客户端</a>
</div>
<a class="close J_close" id='closeId' ytag="21003"></a>
</div>
</div>
1
2
3
4
5
6
7
8
9
10
11
// main.js
e("#showClientId").click(function() {
e(".mod_download").show()
})
e.cookie.get("isShowAppDownAd") || (e.url.getParam("src") != "qqbrowser" && e(".mod_download").show(), e.cookie.add("isShowAppDownAd", 1, "/", 86400))
e("#closeId").click(function() {
e(".mod_download").hide()
})
e("#closeAId").click(function() {
e(".mod_download").hide()
})

屏蔽代码如下:

1
2
3
4
5
6
webView.loadUrl("javascript:"
+ "var s = 'isShowAppDownAd' + '=' + escape(1) + ';path=/';"
+ "var o = new Date;"
+ "o.setTime(o.getTime() + 10 * 86400 * 1e3);"
+ "s += ';expires=' + o.toGMTString();"
+ "document.cookie = s;");

天猫、当当同样可通过设置 Cookie 屏蔽
天猫:

1
2
3
4
webView.loadUrl("javascript:"
+ "var o = new Date;"
+ "o.setTime(o.getTime() + 10 * 86400 * 1e3);"
+ "document.cookie = '_isSmartBannerShowed_=1;expires=' + o.toGMTString() + ';domain=.tmall.com;path=/';");

当当:

1
2
3
4
webView.loadUrl("javascript:"
+ "var o = new Date;"
+ "o.setTime(o.getTime() + 10 * 86400 * 1e3);"
+ "document.cookie = 'MIX_M_dlbar=1;domain=.dangdang.com;expires=' + o.toGMTString() + ';path=/';");

以上是第二种广告处理的方式。

一号店的广告只存在于首页,比较大。而一号店广告相关的代码如下:

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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
define("biz_popupAppDownload", ["common_mcookie", "lib_template_ejs"], function(k, l) {
var o = function() {
var f = 0;
var a = window.localStorage;
if (a) {
var c = a.getItem("apolloDonwloadFlag");
if (c && !isNaN(c)) {
var b = new Date().getTime() - parseInt(c);
if (b >= 0 && b < 24 * 3600 * 1000) {
var e = new Date();
var d = new Date();
d.setTime(parseInt(c));
if (e.getFullYear() == d.getFullYear() && e.getMonth() == d.getMonth() && e.getDate() == d.getDate()) {
f = 1
}
}
}
}
return f
};
var m = function(c) {
var d = websiteurl + "/homePage/ajaxFindAppDownloadInfo.action";
var a = function(e) {
var f = n(e);
if (f) {
$(document.body).append(f);
j()
}
};
var b = {url: c};
$.getJSON(d, b, function(e) {
if (e) {
if (e.status == 1) {
a(e.data)
}
}
})
};
var n = function(b) {
var f = false;
var c = /(iPod|iTouch|iPhone|iPad)/i;
if (c.test(window.navigator.userAgent)) {
f = true
}
var d = websiteurl + "/statics/mglobal/js/biz/popupAppDownload.ejs";
var a = {pathurl: pathurl,isIOS: f,data: b};
var e = new l({url: d}).render(a);
return e
};
var j = function() {
setTimeout(function() {
$("#globalPopupAppDownload").show();
gotracker("2", "h5_global_popupAppDownload_show")
}, 200);
$("#globalPopupAppDownload_close").click(function() {
$("#globalPopupAppDownload").hide();
gotracker("2", "h5_global_popupAppDownload_close")
});
$("#globalPopupAppDownload div.layout_white").get(0).addEventListener("touchmove", function() {
$("#globalPopupAppDownload").hide();
gotracker("2", "h5_global_popupAppDownload_close")
}, false);
$("#globalPopupAppDownload_link1,#globalPopupAppDownload_link2").click(function() {
$("#globalPopupAppDownload").hide();
gotracker("2", $(this).attr("data-ref"))
});
var a = window.localStorage;
if (a) {
a.setItem("apolloDonwloadFlag", new Date().getTime())
}
};
var h = {};
h.init = function(a) {
if (!o() && a) {
m(a)
}
};
return h
});

一号店通过 window.localStorage 记录每次显示广告的时间,key 为 apolloDonwloadFlag,然后将记录时间与当时时间进行比较,如若在 24 小时内,则不会再显示。所以屏蔽的方法就是每次修改 apolloDonwloadFlag 的值为当时时间就好。

屏蔽代码:

1
2
webView.loadUrl("javascript:"
+ "window.localStorage.apolloDonwloadFlag = Date.now();");

京东首页也和一号店一样,处理方式也相同。
屏蔽代码:

1
2
webView.loadUrl("javascript:"
+ "window.localStorage.indexdownCloseDate = Date.now();");

最后就剩淘宝了。首先通过 Chrome 定位淘宝广告条元素位置,代码如下:

1
2
3
4
5
6
7
8
<div id="d8dc344" class="d33dsk">
<a id="d8dc344-close" class="d33-close" href="#"></a>
<a id="d8dc344-open" class="d33-point" href="#">
<p class="d33-font">
<b class="d33-taobao"></b><span>最后24小时,20亿等你拿!</span><b class="d33-dl" style="">立即查看</b>
</p>
</a>
</div>

发现,淘宝广告元素的 ID 和 Class 全都是随机数,-_-这样也就无法通过 DOM 隐藏或 remove 掉了(算你狠)。没办法,接着看 JS 代码,整个都是 JS 实现的。
前面几个都可以依据 Element ID or ClassName 快速找到 JS 代码的相关位置,淘宝虽然使用了随机数,但后缀还是不变的,搜索“-close”,也能定位相关代码位置了(,也可以根据广告条上文字定位)。
然后就会发现淘宝也是使用 localStorage 记录广告条关闭时间。Key 为 closeDate。

相关代码在 g.tbcdn.cn/mtb/ 域下 zepto.js 文件中

总之,分成三种不同的处理方式:

  1. 简单粗暴,直接在页面顶部或底部放置广告元素。没有任何用户体验的优化。如苏宁。可根据 Element ID 或 ClassName 隐藏或 remove 掉。

  2. 使用 Cookie 来标记广告已显示,或被用户关闭。通过设置 Cookie 的有效期来控制时间。找到广告相关的 Cookie Key,设置超长的有效期即可屏蔽。

  3. 使用 localStorage 来储存广告显示时间,或被用户关闭时间。通过与当前时间的对比来控制广告是否被显示。同样找到相关的 Key,设置为当前时间,即可屏蔽。