用反应检测广告块
Detect adblock with react
我正在尝试检测 AdBlock plus 在 Firefox 中是否 运行,它不需要 100% 的时间工作,但我至少想禁用 Firefox 和chrome.
看起来最有希望的解决方案来自这个 blockAdBlock package. They show an example which works,,但它需要对主 index.html 文件进行操作。我正在使用 Gatsby,它并不能真正让您访问 .html 文件,所以我想在我的组件中检测广告拦截器。
他们的blockadblock.js文件里的代码是一个IIFE,我不是很懂,但是我懂的知道是创建的时候调用的。
如果我只是复制粘贴该文件中的代码并将其放入我的组件中,然后尝试检查 adBlocker,看起来 blockAdBlock 永远不会未定义
const BAB = (function(window) {...})(window);
if (typeof blockAdBlock === 'undefined'){ //Always true
alert('works')
canRunAds = false
}
如果他们的示例有效,我觉得我应该能够从中得到一些工作。
我见过的大多数解决方案
我见过的每个 common answer 都使用类似 div 的东西,看起来像
<div id="ad-container">
<img src="../ad/ad.png" id="ad">
</div>
然后使用一些 javascript 来检查 'ad-container' 是否具有 > 1 的高度。我的 div 名称类似于“广告容器”(或广告、广告块) , 广告横幅)不会被广告拦截器删除,所以这个方法是错误的。
FuckAdBlock/BlockAdBlock 库通过模拟 AdBlocker 已知会阻止的模式(特别过滤 CSS 类)并检查它是否被阻止来工作。 (您可以通过分析广告拦截器模式并将它们嵌入您的页面来做类似的事情)。
使用FuckAdBlock 项目示例。通过注入脚本标签在运行时从 cdnjs 动态加载脚本:
// Function called if AdBlock is not detected
function adBlockNotDetected() {
alert('AdBlock is not enabled');
}
// Function called if AdBlock is detected
function adBlockDetected() {
alert('AdBlock is enabled');
}
// We look at whether FuckAdBlock already exists.
if(typeof fuckAdBlock !== 'undefined' || typeof FuckAdBlock !== 'undefined') {
// If this is the case, it means that something tries to usurp are identity
// So, considering that it is a detection
adBlockDetected();
} else {
// Otherwise, you import the script FuckAdBlock
var importFAB = document.createElement('script');
importFAB.onload = function() {
// If all goes well, we configure FuckAdBlock
fuckAdBlock.onDetected(adBlockDetected)
fuckAdBlock.onNotDetected(adBlockNotDetected);
};
importFAB.onerror = function() {
// If the script does not load (blocked, integrity error, ...)
// Then a detection is triggered
adBlockDetected();
};
importFAB.integrity = 'sha256-xjwKUY/NgkPjZZBOtOxRYtK20GaqTwUCf7WYCJ1z69w=';
importFAB.crossOrigin = 'anonymous';
importFAB.src = 'https://cdnjs.cloudflare.com/ajax/libs/fuckadblock/3.2.1/fuckadblock.min.js';
document.head.appendChild(importFAB);
}
使用BlockAdblock 项目示例。包括来自 cdnjs CDN 的 blockadblock.js:
// Function called if AdBlock is not detected
function adBlockNotDetected() {
alert('AdBlock is not enabled');
}
// Function called if AdBlock is detected
function adBlockDetected() {
alert('AdBlock is enabled');
}
// Recommended audit because AdBlock lock the file 'blockadblock.js'
// If the file is not called, the variable does not exist 'blockAdBlock'
// This means that AdBlock is present
if(typeof blockAdBlock === 'undefined') {
adBlockDetected();
} else {
blockAdBlock.onDetected(adBlockDetected);
blockAdBlock.onNotDetected(adBlockNotDetected);
// and|or
blockAdBlock.on(true, adBlockDetected);
blockAdBlock.on(false, adBlockNotDetected);
// and|or
blockAdBlock.on(true, adBlockDetected).onNotDetected(adBlockNotDetected);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/blockadblock/3.2.1/blockadblock.min.js" integrity="sha512-EFY34xQ/AKRSb4EfjeRCO1TXnLuDQrYlo3BVId+DU8J4BiKUezCWK93bUlXTkEf4a8rMRroouaPXHnq/WTK4pA==" crossorigin="anonymous"></script>
只检查 iframe 的高度对我有用:
(使用 ResizeObserver 在 iframe 大小变化时挂钩。由于缺少 ResizeObserver 支持,5 秒后设置超时。)
注意:检查上面 link 中的支持 table and/or 为 ResizeObserver 使用 polyfill。
例如:iOS Safari 仅 13.4+,这可能无法接受table 对许多人的支持级别
fn = () => document.querySelector('.jellyWidget').clientHeight > 0 || alert('blocked')
fn()
setTimeout(fn,5000)
typeof ResizeObserver!=='undefined' &&
new ResizeObserver(fn).observe(document.querySelector('.jellyWidget'))
fn = () => document.querySelector('.jellyWidget').clientHeight > 0 || alert('blocked')
fn()
setTimeout(fn,5000)
typeof ResizeObserver!=='undefined' &&
new ResizeObserver(fn).observe(document.querySelector('.jellyWidget'))
<iframe src="//rcm-na.amazon-adsystem.com/e/cm?o=15&p=14&l=ur1&category=biss&banner=05GNDH2E5A6MQH5KAZ02&f=ifr&linkID=3980418b7a5cc00e6f0e0fac51cf69f9&t=suddenlysas06-20&tracking_id=suddenlysas06-20" scrolling="no" style="border: medium none;" class="jellyWidget undefined" width="160" height="600">#document<head><script type="text/javascript">
/**
* Created by pedapav on 4/1/15.
*
* Tracking utilities to be used by client side rendering templates.
*/
window["trackingUtils"] = function(regionInt, foresterChannelUrlPrefix, impressionRecorderPrefix, pixelUrl,
clickUrl, impressionToken, slotNum, subtag, ABPPixelURL, disableABPCheck, AESPixelUrl) {
var that = {},
refMatch = new RegExp("\/(ref=[\w]+)\/\?", "i"),
TRANSIT_ID_KEY = "assocPayloadId",
encodeStr = function (b) {
return b && encodeURIComponent(b).replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
},
rawRefURL = (function() {
var alink = document.createElement("a");
alink.href = (window.location !== window.parent.location) ? document.referrer : document.location;
// on IE, path name does not begin with a '/' - append it.
// on IE, 'host' property includes the port even if it is standard port 80/443
// but on IE, document.location.href does not include standard ports
// so we have to remove them before forming 'ref-refUrl'
return alink.protocol + "//" + alink.hostname +
((alink.port === "" || alink.port === "80" || alink.port === "443") ? "" : (":" + alink.port)) +
(alink.pathname.indexOf("/") !== 0 ? ("/" + alink.pathname) : alink.pathname);
}()),
refRefURL = (function() {
return encodeStr(rawRefURL);
}()),
addQueryParameter = function(linkElem, paramName, paramValue, overwrite) {
if(typeof paramValue === "string" && paramValue !== "") {
if (linkElem.search === "") {
linkElem.search = "?" + paramName + "=" + paramValue;
} else if(!linkElem.search.match(new RegExp("[?&]" + paramName + "="))) {
linkElem.search = linkElem.search.replace(/\?/, "?" + paramName + "=" + paramValue + "&");
} else if(overwrite) {
// query parameter already present - overwrite it, if forced
linkElem.search = linkElem.search.replace(new RegExp(paramName + "=([^&]*)"), paramName + "=" + paramValue);
}
}
return linkElem;
},
addQueryParameterStr = function(linkTarget, paramName, paramValue) {
if(typeof paramValue === "string" && paramValue !== "") {
if (!linkTarget.match(/\?/)) {
linkTarget = linkTarget + "?" + paramName + "=" + paramValue;
} else if(!linkTarget.match(paramName)) {
linkTarget = linkTarget.replace(/\?/, "?" + paramName + "=" + paramValue + "&");
}
}
return linkTarget;
},
getEffectiveSlotNum = function(localSlotNum) {
var finalSlotNum = (typeof slotNum !== "undefined") ? slotNum : 0;
if(typeof localSlotNum !== "undefined") finalSlotNum = localSlotNum;
return finalSlotNum;
};
that.addRefUrls = function (allLinks, linkId, linkCode, trackingId) {
var amazonLinkPattern = new RegExp("^http://.*(amazon|endless|myhabit|amazonwireless|javari|smallparts)\.(com|ca|co\.jp|de|fr|co\.uk|cn|it|es)/.*", "i"),
href, results, i;
for (i = 0; i < allLinks.length; i++) {
allLinks[i].rel = "nofollow";
href = String(allLinks[i].href);
if (results = href.match(amazonLinkPattern)) {
allLinks[i].href = that.addTrackingParameters(allLinks[i], linkId, linkCode, trackingId);
}
}
};
that.addRefRefUrl = function(linkElem) {
return addQueryParameter(linkElem, "ref-refURL", refRefURL);
};
that.getRefRefUrl = function() {
return refRefURL;
};
that.getRawRefUrl = function() {
return rawRefURL;
};
that.addSignature = function(linkElem, signature, signatureTimeStamp) {
return addQueryParameter(
addQueryParameter(linkElem, "sig", signature),
"sigts", signatureTimeStamp);
};
that.addLinkCode = function(linkElem, linkCode) {
return addQueryParameter(linkElem, "linkCode", linkCode);
};
that.addTrackingId = function(linkElem, trackingId) {
return addQueryParameter(linkElem, "tag", trackingId);
};
that.addLinkId = function(linkElem, linkId) {
return addQueryParameter(linkElem, "linkId", linkId);
};
that.addSubtag = function(linkElem, subtag) {
return addQueryParameter(linkElem, "ascsubtag", subtag);
};
that.addCreativeAsin = function(linkElem, adId){
return addQueryParameter(addQueryParameter(linkElem, "creativeASIN", adId), "adId", adId);
};
that.addAdType = function(linkElem, adType) {
return addQueryParameter(linkElem, 'adType', adType);
};
that.addAdMode = function(linkElem, adMode) {
return addQueryParameter(linkElem, 'adMode', adMode);
};
that.addAdFormat = function(linkElem, adFormat) {
return addQueryParameter(linkElem, 'adFormat', adFormat);
};
that.addImpressionTimestamp = function(linkElem, impressionTimestamp) {
if (typeof impressionTimestamp === "number") impressionTimestamp = impressionTimestamp.toString();
return addQueryParameter(linkElem, 'impressionTimestamp', impressionTimestamp);
};
that.convertToRedirectedUrl = function(linkElem, prefix, destParamName) {
var alink = document.createElement("a");
alink.setAttribute("href", prefix);
if(typeof destParamName !== "undefined") {
addQueryParameter(alink, destParamName, encodeStr(linkElem.getAttribute("href")), true);
} else {
alink.setAttribute("href", prefix + "/" + alink.getAttribute("href"));
}
linkElem.setAttribute("href", alink.getAttribute("href"));
return linkElem;
};
that.getImpressionToken = function() {
return impressionToken;
};
//we are using impressionToken as transitId right now,
//can be changed to GUID in future
that.generateTransitId = function() {
return that.getHashedImpressionToken();
};
that.getHashedImpressionToken = function(){
var pixelUrlParts = pixelUrl.split("/");
//pixelUrl is http://pixelurl.com/x/px/HASHEDIMPRESSIONTOKEN/
var hashedImpressionToken = pixelUrlParts[pixelUrlParts.length - 2]
return hashedImpressionToken;
};
that.getTransitId = function(){
if(typeof assoc_session_storage !== "undefined"){
var existingTransitId = assoc_session_storage.get(TRANSIT_ID_KEY);
return existingTransitId;
}
return null;
};
that.getClickUrl = function() {
return clickUrl;
};
that.addImpressionToken = function(linkElem, localSlotNum) {
var finalSlotNum = getEffectiveSlotNum(localSlotNum);
if(typeof impressionToken === "string" && impressionToken !== "") {
addQueryParameter(linkElem, "imprToken", impressionToken);
if(typeof finalSlotNum !== "undefined") addQueryParameter(linkElem, "slotNum", finalSlotNum);
}
return linkElem;
};
that.addImpressionTokenStr = function(url, localSlotNum) {
var finalSlotNum = getEffectiveSlotNum(localSlotNum);
if(typeof impressionToken === "string" && impressionToken !== "") {
url = addQueryParameterStr(url, "imprToken", impressionToken);
if(typeof finalSlotNum !== "undefined") url = addQueryParameterStr(url, "slotNum", finalSlotNum);
}
return url;
};
that.addTrackingParameters = function(linkElem, linkId, linkCode, trackingId, refMarker, creativeASIN, signature, signatureTimeStamp, adType, adMode, adFormat, impressionTimestamp) {
return that.addSignature(
that.addCreativeAsin(
that.addLinkId(
that.addTrackingId(
that.addSubtag(
that.addLinkCode(
that.addRefRefUrl(
that.addImpressionToken(
that.addRefMarker(
that.addAdType(
that.addAdMode(
that.addAdFormat(
that.addImpressionTimestamp(linkElem, impressionTimestamp),
adFormat),
adMode),
adType),
refMarker))),
linkCode),
subtag),
trackingId),
linkId),
creativeASIN),
signature, signatureTimeStamp
);
};
that.addRefMarker = function(linkElem, refMarker) {
var match, endsWithSlash = false;
if(typeof refMarker === "undefined") return linkElem;
if(match = linkElem.pathname.match(refMatch)) {
linkElem.pathname = linkElem.pathname.replace(match[1], "ref=" + refMarker);
} else {
endsWithSlash = (linkElem.pathname.charAt(linkElem.pathname.length - 1) === '/');
linkElem.pathname = linkElem.pathname + (endsWithSlash ? "" : "/") + "ref=" + refMarker;
}
return linkElem;
};
that.getRefMarker = function(linkElem) {
var match;
if(match = linkElem.pathname.match(refMatch)) {
return match[1].substr(4);
} else return undefined;
};
that.getCurrentURL = function(){
return (window.location !== window.parent.location) ? document.referrer : document.location.href;
}
that.makeForesterCall = function(data) {
var finalAAXPixelUrl = undefined, json;
if(typeof JSON !== 'undefined') json = JSON.stringify(data);
else if(typeof amzn_assoc_utils !== "undefined" && typeof amzn_assoc_utils["stringify"] === "function") json = amzn_assoc_utils.stringify(data);
else return;
if(typeof pixelUrl === "string") {
finalAAXPixelUrl = pixelUrl + "?assoc_payload=" + encodeURIComponent(json);
that.generateImage(finalAAXPixelUrl);
}
};
that.recordImpression = function(linkCode, trackingId, data, skipIRCall, slotNum) {
data["linkCode"] = linkCode;
data["trackingId"] = trackingId;
data["refUrl"] = that.getCurrentURL();
if(disableABPCheck || !ABPPixelURL) {
that.makeForesterCall(data);
} else {
that.addABPFlag(data, that.makeForesterCall);
}
};
that.createAssocPayload = function(data, linkCode, trackingId, refUrl){
data["linkCode"] = linkCode;
data["trackingId"] = trackingId;
data["refUrl"] = refUrl;
var stringifiedData = "";
if(typeof amzn_assoc_utils !== "undefined" && typeof amzn_assoc_utils["stringify"] === "function")
stringifiedData = amzn_assoc_utils.stringify(data);
return stringifiedData;
}
that.recordAESImpression = function(linkCode, trackingId, data){
if(typeof AESPixelUrl === "string") {
var assocPayload = that.createAssocPayload(data, linkCode, trackingId, that.getCurrentURL());
var hashedImpressionToken = that.getHashedImpressionToken();
var finalAESPixelUrl = AESPixelUrl + hashedImpressionToken+"/pixel?assoc_payload=" + encodeURIComponent(assocPayload);
that.generateImage(finalAESPixelUrl);
}
};
that.recordTransit = function(){
//if transitId is not present or blog has utm_param in url, set new transitId
if(!(that.getTransitId()) || that.isUTMParamPresentInUrl(that.getCurrentURL())){
assoc_session_storage.set(TRANSIT_ID_KEY, that.generateTransitId());
}
}
that.isUTMParamPresentInUrl = function(url){
var utmParamExists = url.match(/utm_source=/i);
return (utmParamExists !== null);
}
that.addAAXClickUrls = function(links){
var aaxClickUrl, i, href;
//convert all given links with AAX click urls
if(typeof links === 'undefined' || typeof clickUrl === 'undefined') return;
for (i = 0; i < links.length; i++) {
href = String(links[i].href);
if(href.indexOf(clickUrl) < 0) {
aaxClickUrl = clickUrl + href;
links[i].href = aaxClickUrl;
}
}
};
that.addAAXClickUrl = function(url){
//append given url with AAX click url
if(typeof url === 'undefined' || url.indexOf(clickUrl) === 0) return url;
return clickUrl + url;
};
that.updateLinks = function(links, updaterFunc) {
var i, href;
if(typeof updaterFunc !== "function") return;
for(i = 0; i < links.length; i++) {
href = String(links[i].href);
links[i].href = updaterFunc(href);
}
};
that.elementInViewPort = function(el) {
var rect = el.getBoundingClientRect(),
inViewPort = (
rect.top >= 0 &&
rect.left >= 0 &&
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
rect.right <= (window.innerWidth || document.documentElement.clientWidth)
);
return {
"posX": rect.left + window.pageXOffset,
"posY": rect.top + window.pageYOffset,
"inViewPort": inViewPort
};
};
that.recordViewability = function(slotNum, aboveTheFold, topPos, leftPos){
if(typeof pixelUrl === "string") {
var payload = that.createViewbilityPayload(slotNum, aboveTheFold, topPos, leftPos);
var finalAAXPixelUrl = pixelUrl + payload + "&cb=" + (new Date()).getTime();
that.generateImage(finalAAXPixelUrl);
}
};
that.recordAESViewability = function(slotNum, aboveTheFold, topPos, leftPos){
if(typeof AESPixelUrl === "string") {
var payload = that.createViewbilityPayload(slotNum, aboveTheFold, topPos, leftPos);
var hashedImpressionToken = that.getHashedImpressionToken();
var encodedPayload = encodeURIComponent(payload);
var finalAESPixelUrl = AESPixelUrl + hashedImpressionToken + "/pixel/"+encodedPayload
+ "&cb=" + (new Date()).getTime();
that.generateImage(finalAESPixelUrl);
}
};
that.createViewbilityPayload = function(slotNum, aboveTheFold, topPos, leftPos){
var viewbilityAttr = {};
if(typeof aboveTheFold !== "undefined") viewbilityAttr["above_the_fold"] = aboveTheFold;
if(typeof topPos !== "undefined") viewbilityAttr["topPos"] = topPos;
if(typeof leftPos !== "undefined") viewbilityAttr["leftPos"] = leftPos;
if(typeof slotNum !== "undefined"){
//handling case when only slotnum is passed
if (Object.keys(viewbilityAttr).length === 0)
viewbilityAttr["viewable"] = true;
viewbilityAttr["slotNum"] = slotNum;
}
var stringifiedData = "";
if(typeof amzn_assoc_utils !== "undefined" && typeof amzn_assoc_utils["stringify"] === "function")
stringifiedData = amzn_assoc_utils.stringify({"adViewability":[viewbilityAttr]});
return stringifiedData;
};
that.generateImage = function(imageSrc){
if(typeof imageSrc !== "undefined")
(new Image()).src = imageSrc;
};
that.addABPFlag = function(data, callback) {
var detected = false,
checksRemain = 2,
img1 = document.body ? document.body.appendChild(new Image()) : new Image(),
img2 = document.body ? document.body.appendChild(new Image()) : new Image(),
error1 = false,
error2 = false,
random = Math.random() * 11,
px = ABPPixelURL + "?ch=*&rn=*",
beforeCheck = function(callback, timeout) {
if (checksRemain === 0 || timeout > 1E3) {
data.supplySideMetadata = {
ABPInstalled: checksRemain === 0 && detected
};
callback(data);
} else {
setTimeout(function() {
beforeCheck(callback, timeout * 2);
}, timeout * 2);
}
},
checkImages = function() {
if(--checksRemain)
return;
detected = !error1 && error2;
};
img1.style.display = "none";
img2.style.display = "none";
img1.onload = checkImages;
img1.onerror = function() {
error1 = true;
checkImages();
};
img1.src = px.replace(/\*/, 1).replace(/\*/, random);
img2.onload = checkImages;
img2.onerror = function() {
error2 = true;
checkImages();
};
img2.src = px.replace(/\*/, 2).replace(/\*/, random);
beforeCheck(callback, 250);
};
return that;
};
if(typeof amzn_assoc_utils === "undefined") {
amzn_assoc_utils = {};
}
</head>
<body style="margin-bottom: 0px; margin-top: 0px;" class="vsc-initialized" marginwidth="0">
<div id="amznBanners_assoc_banner_placement_default_${slotNum}_div">
<img id="amznBanners_assoc_banner_placement_default_${slotNum}_img" usemap="#amznBanners_assoc_banner_placement_default_${slotNum}_boxmap" src="https://images-na.ssl-images-amazon.com/images/G/15/img15/biss/Associates/24569-CA-BISS-21Aug-frassco_160x600._V313078032_.png">
<map name="amznBanners_assoc_banner_placement_default_${slotNum}_boxmap">
<area id="amznBanners_assoc_banner_placement_default_${slotNum}_privacybox" shape="rect" coords="(0,588,160,600)" href="http://rcm-na.amazon-adsystem.com/e/cm/privacy-policy.html?o=15" target="_top" rel="nofollow">
<area id="amznBanners_assoc_banner_placement_default_${slotNum}_a" shape="rect" coords="0,0,10000,10000" href="https://www.amazon.ca/b?tag=suddenlysas06-20&linkCode=ur1&node=11076213011" target="_top" rel="nofollow">
</map>
</div>
<script type="text/javascript">
amzn_assoc_ad_spec.isIframe = true;
amzn_assoc_ad_spec.linkCode = "ur1";
window.amznBannerAd(amzn_assoc_ad_spec).init();
var amazon_assoc_ir_f_call_associates_ads = function(map) {
var logTypeStr = "", foresterURL, json;
if(typeof JSON !== 'undefined') json = JSON.stringify(map);
else if(typeof amzn_assoc_utils !== 'undefined') json = amzn_assoc_utils.stringify(map);
else return;
if(typeof map.logType !== "undefined") logTypeStr = "&logType=" + map.logType;
// forester URLs are of format //<end_point>/<api_version>/<channel_id>/<channel_version>/<OPERATION>/
// Depending on operation, we either pass the data in the URI or we pass them as query parameters
// if operation is OP, data must be in query parameters while if operation is TOP,
// data must be in the URI itself
foresterURL = "//fls-na.amazon-adsystem.com/1/associates-ads/1/OP/r/json";
foresterURL = foresterURL + "?cb=" + (new Date()).getTime() + logTypeStr + "&p=" + encodeURIComponent(json);
(new Image()).src = foresterURL;
};
var amazon_assoc_ir_f_call = amazon_assoc_ir_f_call_associates_ads;
</script>
</body></iframe>
注意:这不会检测到普通的可见性隐藏(他们使用注入样式使它们不可见而不是阻塞和折叠)或更复杂的阻塞,如果(可能是“何时”)最终会发生这演变成一场(反)广告拦截器军备竞赛。这是一场你赢不了的比赛,而且可能会激怒你的用户。只是对它“友善”应该可以避免这种情况,选择大部分“不引人注目”的基于文本的广告并通过电子邮件向广告拦截器团队发送电子邮件以将您列入不引人注目的列表是另一种选择。
但是,我强调这一点,这是你的决定。
我的功能广告拦截器
const _handleNavigation = async () => {
dispatch('RESET_CONTEXT');
try {
const url = `https://ads.google.com?=${new Date().getTime()}`;
await axios.get(url);
router.push('/post');
} catch (error) {
enqueueSnackbar(`Please disable your ad blocker to post`, snackbar.ERROR_TOP_CENTER);
}
};
我正在尝试检测 AdBlock plus 在 Firefox 中是否 运行,它不需要 100% 的时间工作,但我至少想禁用 Firefox 和chrome.
看起来最有希望的解决方案来自这个 blockAdBlock package. They show an example which works,,但它需要对主 index.html 文件进行操作。我正在使用 Gatsby,它并不能真正让您访问 .html 文件,所以我想在我的组件中检测广告拦截器。
他们的blockadblock.js文件里的代码是一个IIFE,我不是很懂,但是我懂的知道是创建的时候调用的。
如果我只是复制粘贴该文件中的代码并将其放入我的组件中,然后尝试检查 adBlocker,看起来 blockAdBlock 永远不会未定义
const BAB = (function(window) {...})(window);
if (typeof blockAdBlock === 'undefined'){ //Always true
alert('works')
canRunAds = false
}
如果他们的示例有效,我觉得我应该能够从中得到一些工作。
我见过的大多数解决方案
我见过的每个 common answer 都使用类似 div 的东西,看起来像
<div id="ad-container">
<img src="../ad/ad.png" id="ad">
</div>
然后使用一些 javascript 来检查 'ad-container' 是否具有 > 1 的高度。我的 div 名称类似于“广告容器”(或广告、广告块) , 广告横幅)不会被广告拦截器删除,所以这个方法是错误的。
FuckAdBlock/BlockAdBlock 库通过模拟 AdBlocker 已知会阻止的模式(特别过滤 CSS 类)并检查它是否被阻止来工作。 (您可以通过分析广告拦截器模式并将它们嵌入您的页面来做类似的事情)。
使用FuckAdBlock 项目示例。通过注入脚本标签在运行时从 cdnjs 动态加载脚本:
// Function called if AdBlock is not detected
function adBlockNotDetected() {
alert('AdBlock is not enabled');
}
// Function called if AdBlock is detected
function adBlockDetected() {
alert('AdBlock is enabled');
}
// We look at whether FuckAdBlock already exists.
if(typeof fuckAdBlock !== 'undefined' || typeof FuckAdBlock !== 'undefined') {
// If this is the case, it means that something tries to usurp are identity
// So, considering that it is a detection
adBlockDetected();
} else {
// Otherwise, you import the script FuckAdBlock
var importFAB = document.createElement('script');
importFAB.onload = function() {
// If all goes well, we configure FuckAdBlock
fuckAdBlock.onDetected(adBlockDetected)
fuckAdBlock.onNotDetected(adBlockNotDetected);
};
importFAB.onerror = function() {
// If the script does not load (blocked, integrity error, ...)
// Then a detection is triggered
adBlockDetected();
};
importFAB.integrity = 'sha256-xjwKUY/NgkPjZZBOtOxRYtK20GaqTwUCf7WYCJ1z69w=';
importFAB.crossOrigin = 'anonymous';
importFAB.src = 'https://cdnjs.cloudflare.com/ajax/libs/fuckadblock/3.2.1/fuckadblock.min.js';
document.head.appendChild(importFAB);
}
使用BlockAdblock 项目示例。包括来自 cdnjs CDN 的 blockadblock.js:
// Function called if AdBlock is not detected
function adBlockNotDetected() {
alert('AdBlock is not enabled');
}
// Function called if AdBlock is detected
function adBlockDetected() {
alert('AdBlock is enabled');
}
// Recommended audit because AdBlock lock the file 'blockadblock.js'
// If the file is not called, the variable does not exist 'blockAdBlock'
// This means that AdBlock is present
if(typeof blockAdBlock === 'undefined') {
adBlockDetected();
} else {
blockAdBlock.onDetected(adBlockDetected);
blockAdBlock.onNotDetected(adBlockNotDetected);
// and|or
blockAdBlock.on(true, adBlockDetected);
blockAdBlock.on(false, adBlockNotDetected);
// and|or
blockAdBlock.on(true, adBlockDetected).onNotDetected(adBlockNotDetected);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/blockadblock/3.2.1/blockadblock.min.js" integrity="sha512-EFY34xQ/AKRSb4EfjeRCO1TXnLuDQrYlo3BVId+DU8J4BiKUezCWK93bUlXTkEf4a8rMRroouaPXHnq/WTK4pA==" crossorigin="anonymous"></script>
只检查 iframe 的高度对我有用:
(使用 ResizeObserver 在 iframe 大小变化时挂钩。由于缺少 ResizeObserver 支持,5 秒后设置超时。)
注意:检查上面 link 中的支持 table and/or 为 ResizeObserver 使用 polyfill。
例如:iOS Safari 仅 13.4+,这可能无法接受table 对许多人的支持级别
fn = () => document.querySelector('.jellyWidget').clientHeight > 0 || alert('blocked')
fn()
setTimeout(fn,5000)
typeof ResizeObserver!=='undefined' &&
new ResizeObserver(fn).observe(document.querySelector('.jellyWidget'))
fn = () => document.querySelector('.jellyWidget').clientHeight > 0 || alert('blocked')
fn()
setTimeout(fn,5000)
typeof ResizeObserver!=='undefined' &&
new ResizeObserver(fn).observe(document.querySelector('.jellyWidget'))
<iframe src="//rcm-na.amazon-adsystem.com/e/cm?o=15&p=14&l=ur1&category=biss&banner=05GNDH2E5A6MQH5KAZ02&f=ifr&linkID=3980418b7a5cc00e6f0e0fac51cf69f9&t=suddenlysas06-20&tracking_id=suddenlysas06-20" scrolling="no" style="border: medium none;" class="jellyWidget undefined" width="160" height="600">#document<head><script type="text/javascript">
/**
* Created by pedapav on 4/1/15.
*
* Tracking utilities to be used by client side rendering templates.
*/
window["trackingUtils"] = function(regionInt, foresterChannelUrlPrefix, impressionRecorderPrefix, pixelUrl,
clickUrl, impressionToken, slotNum, subtag, ABPPixelURL, disableABPCheck, AESPixelUrl) {
var that = {},
refMatch = new RegExp("\/(ref=[\w]+)\/\?", "i"),
TRANSIT_ID_KEY = "assocPayloadId",
encodeStr = function (b) {
return b && encodeURIComponent(b).replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
},
rawRefURL = (function() {
var alink = document.createElement("a");
alink.href = (window.location !== window.parent.location) ? document.referrer : document.location;
// on IE, path name does not begin with a '/' - append it.
// on IE, 'host' property includes the port even if it is standard port 80/443
// but on IE, document.location.href does not include standard ports
// so we have to remove them before forming 'ref-refUrl'
return alink.protocol + "//" + alink.hostname +
((alink.port === "" || alink.port === "80" || alink.port === "443") ? "" : (":" + alink.port)) +
(alink.pathname.indexOf("/") !== 0 ? ("/" + alink.pathname) : alink.pathname);
}()),
refRefURL = (function() {
return encodeStr(rawRefURL);
}()),
addQueryParameter = function(linkElem, paramName, paramValue, overwrite) {
if(typeof paramValue === "string" && paramValue !== "") {
if (linkElem.search === "") {
linkElem.search = "?" + paramName + "=" + paramValue;
} else if(!linkElem.search.match(new RegExp("[?&]" + paramName + "="))) {
linkElem.search = linkElem.search.replace(/\?/, "?" + paramName + "=" + paramValue + "&");
} else if(overwrite) {
// query parameter already present - overwrite it, if forced
linkElem.search = linkElem.search.replace(new RegExp(paramName + "=([^&]*)"), paramName + "=" + paramValue);
}
}
return linkElem;
},
addQueryParameterStr = function(linkTarget, paramName, paramValue) {
if(typeof paramValue === "string" && paramValue !== "") {
if (!linkTarget.match(/\?/)) {
linkTarget = linkTarget + "?" + paramName + "=" + paramValue;
} else if(!linkTarget.match(paramName)) {
linkTarget = linkTarget.replace(/\?/, "?" + paramName + "=" + paramValue + "&");
}
}
return linkTarget;
},
getEffectiveSlotNum = function(localSlotNum) {
var finalSlotNum = (typeof slotNum !== "undefined") ? slotNum : 0;
if(typeof localSlotNum !== "undefined") finalSlotNum = localSlotNum;
return finalSlotNum;
};
that.addRefUrls = function (allLinks, linkId, linkCode, trackingId) {
var amazonLinkPattern = new RegExp("^http://.*(amazon|endless|myhabit|amazonwireless|javari|smallparts)\.(com|ca|co\.jp|de|fr|co\.uk|cn|it|es)/.*", "i"),
href, results, i;
for (i = 0; i < allLinks.length; i++) {
allLinks[i].rel = "nofollow";
href = String(allLinks[i].href);
if (results = href.match(amazonLinkPattern)) {
allLinks[i].href = that.addTrackingParameters(allLinks[i], linkId, linkCode, trackingId);
}
}
};
that.addRefRefUrl = function(linkElem) {
return addQueryParameter(linkElem, "ref-refURL", refRefURL);
};
that.getRefRefUrl = function() {
return refRefURL;
};
that.getRawRefUrl = function() {
return rawRefURL;
};
that.addSignature = function(linkElem, signature, signatureTimeStamp) {
return addQueryParameter(
addQueryParameter(linkElem, "sig", signature),
"sigts", signatureTimeStamp);
};
that.addLinkCode = function(linkElem, linkCode) {
return addQueryParameter(linkElem, "linkCode", linkCode);
};
that.addTrackingId = function(linkElem, trackingId) {
return addQueryParameter(linkElem, "tag", trackingId);
};
that.addLinkId = function(linkElem, linkId) {
return addQueryParameter(linkElem, "linkId", linkId);
};
that.addSubtag = function(linkElem, subtag) {
return addQueryParameter(linkElem, "ascsubtag", subtag);
};
that.addCreativeAsin = function(linkElem, adId){
return addQueryParameter(addQueryParameter(linkElem, "creativeASIN", adId), "adId", adId);
};
that.addAdType = function(linkElem, adType) {
return addQueryParameter(linkElem, 'adType', adType);
};
that.addAdMode = function(linkElem, adMode) {
return addQueryParameter(linkElem, 'adMode', adMode);
};
that.addAdFormat = function(linkElem, adFormat) {
return addQueryParameter(linkElem, 'adFormat', adFormat);
};
that.addImpressionTimestamp = function(linkElem, impressionTimestamp) {
if (typeof impressionTimestamp === "number") impressionTimestamp = impressionTimestamp.toString();
return addQueryParameter(linkElem, 'impressionTimestamp', impressionTimestamp);
};
that.convertToRedirectedUrl = function(linkElem, prefix, destParamName) {
var alink = document.createElement("a");
alink.setAttribute("href", prefix);
if(typeof destParamName !== "undefined") {
addQueryParameter(alink, destParamName, encodeStr(linkElem.getAttribute("href")), true);
} else {
alink.setAttribute("href", prefix + "/" + alink.getAttribute("href"));
}
linkElem.setAttribute("href", alink.getAttribute("href"));
return linkElem;
};
that.getImpressionToken = function() {
return impressionToken;
};
//we are using impressionToken as transitId right now,
//can be changed to GUID in future
that.generateTransitId = function() {
return that.getHashedImpressionToken();
};
that.getHashedImpressionToken = function(){
var pixelUrlParts = pixelUrl.split("/");
//pixelUrl is http://pixelurl.com/x/px/HASHEDIMPRESSIONTOKEN/
var hashedImpressionToken = pixelUrlParts[pixelUrlParts.length - 2]
return hashedImpressionToken;
};
that.getTransitId = function(){
if(typeof assoc_session_storage !== "undefined"){
var existingTransitId = assoc_session_storage.get(TRANSIT_ID_KEY);
return existingTransitId;
}
return null;
};
that.getClickUrl = function() {
return clickUrl;
};
that.addImpressionToken = function(linkElem, localSlotNum) {
var finalSlotNum = getEffectiveSlotNum(localSlotNum);
if(typeof impressionToken === "string" && impressionToken !== "") {
addQueryParameter(linkElem, "imprToken", impressionToken);
if(typeof finalSlotNum !== "undefined") addQueryParameter(linkElem, "slotNum", finalSlotNum);
}
return linkElem;
};
that.addImpressionTokenStr = function(url, localSlotNum) {
var finalSlotNum = getEffectiveSlotNum(localSlotNum);
if(typeof impressionToken === "string" && impressionToken !== "") {
url = addQueryParameterStr(url, "imprToken", impressionToken);
if(typeof finalSlotNum !== "undefined") url = addQueryParameterStr(url, "slotNum", finalSlotNum);
}
return url;
};
that.addTrackingParameters = function(linkElem, linkId, linkCode, trackingId, refMarker, creativeASIN, signature, signatureTimeStamp, adType, adMode, adFormat, impressionTimestamp) {
return that.addSignature(
that.addCreativeAsin(
that.addLinkId(
that.addTrackingId(
that.addSubtag(
that.addLinkCode(
that.addRefRefUrl(
that.addImpressionToken(
that.addRefMarker(
that.addAdType(
that.addAdMode(
that.addAdFormat(
that.addImpressionTimestamp(linkElem, impressionTimestamp),
adFormat),
adMode),
adType),
refMarker))),
linkCode),
subtag),
trackingId),
linkId),
creativeASIN),
signature, signatureTimeStamp
);
};
that.addRefMarker = function(linkElem, refMarker) {
var match, endsWithSlash = false;
if(typeof refMarker === "undefined") return linkElem;
if(match = linkElem.pathname.match(refMatch)) {
linkElem.pathname = linkElem.pathname.replace(match[1], "ref=" + refMarker);
} else {
endsWithSlash = (linkElem.pathname.charAt(linkElem.pathname.length - 1) === '/');
linkElem.pathname = linkElem.pathname + (endsWithSlash ? "" : "/") + "ref=" + refMarker;
}
return linkElem;
};
that.getRefMarker = function(linkElem) {
var match;
if(match = linkElem.pathname.match(refMatch)) {
return match[1].substr(4);
} else return undefined;
};
that.getCurrentURL = function(){
return (window.location !== window.parent.location) ? document.referrer : document.location.href;
}
that.makeForesterCall = function(data) {
var finalAAXPixelUrl = undefined, json;
if(typeof JSON !== 'undefined') json = JSON.stringify(data);
else if(typeof amzn_assoc_utils !== "undefined" && typeof amzn_assoc_utils["stringify"] === "function") json = amzn_assoc_utils.stringify(data);
else return;
if(typeof pixelUrl === "string") {
finalAAXPixelUrl = pixelUrl + "?assoc_payload=" + encodeURIComponent(json);
that.generateImage(finalAAXPixelUrl);
}
};
that.recordImpression = function(linkCode, trackingId, data, skipIRCall, slotNum) {
data["linkCode"] = linkCode;
data["trackingId"] = trackingId;
data["refUrl"] = that.getCurrentURL();
if(disableABPCheck || !ABPPixelURL) {
that.makeForesterCall(data);
} else {
that.addABPFlag(data, that.makeForesterCall);
}
};
that.createAssocPayload = function(data, linkCode, trackingId, refUrl){
data["linkCode"] = linkCode;
data["trackingId"] = trackingId;
data["refUrl"] = refUrl;
var stringifiedData = "";
if(typeof amzn_assoc_utils !== "undefined" && typeof amzn_assoc_utils["stringify"] === "function")
stringifiedData = amzn_assoc_utils.stringify(data);
return stringifiedData;
}
that.recordAESImpression = function(linkCode, trackingId, data){
if(typeof AESPixelUrl === "string") {
var assocPayload = that.createAssocPayload(data, linkCode, trackingId, that.getCurrentURL());
var hashedImpressionToken = that.getHashedImpressionToken();
var finalAESPixelUrl = AESPixelUrl + hashedImpressionToken+"/pixel?assoc_payload=" + encodeURIComponent(assocPayload);
that.generateImage(finalAESPixelUrl);
}
};
that.recordTransit = function(){
//if transitId is not present or blog has utm_param in url, set new transitId
if(!(that.getTransitId()) || that.isUTMParamPresentInUrl(that.getCurrentURL())){
assoc_session_storage.set(TRANSIT_ID_KEY, that.generateTransitId());
}
}
that.isUTMParamPresentInUrl = function(url){
var utmParamExists = url.match(/utm_source=/i);
return (utmParamExists !== null);
}
that.addAAXClickUrls = function(links){
var aaxClickUrl, i, href;
//convert all given links with AAX click urls
if(typeof links === 'undefined' || typeof clickUrl === 'undefined') return;
for (i = 0; i < links.length; i++) {
href = String(links[i].href);
if(href.indexOf(clickUrl) < 0) {
aaxClickUrl = clickUrl + href;
links[i].href = aaxClickUrl;
}
}
};
that.addAAXClickUrl = function(url){
//append given url with AAX click url
if(typeof url === 'undefined' || url.indexOf(clickUrl) === 0) return url;
return clickUrl + url;
};
that.updateLinks = function(links, updaterFunc) {
var i, href;
if(typeof updaterFunc !== "function") return;
for(i = 0; i < links.length; i++) {
href = String(links[i].href);
links[i].href = updaterFunc(href);
}
};
that.elementInViewPort = function(el) {
var rect = el.getBoundingClientRect(),
inViewPort = (
rect.top >= 0 &&
rect.left >= 0 &&
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
rect.right <= (window.innerWidth || document.documentElement.clientWidth)
);
return {
"posX": rect.left + window.pageXOffset,
"posY": rect.top + window.pageYOffset,
"inViewPort": inViewPort
};
};
that.recordViewability = function(slotNum, aboveTheFold, topPos, leftPos){
if(typeof pixelUrl === "string") {
var payload = that.createViewbilityPayload(slotNum, aboveTheFold, topPos, leftPos);
var finalAAXPixelUrl = pixelUrl + payload + "&cb=" + (new Date()).getTime();
that.generateImage(finalAAXPixelUrl);
}
};
that.recordAESViewability = function(slotNum, aboveTheFold, topPos, leftPos){
if(typeof AESPixelUrl === "string") {
var payload = that.createViewbilityPayload(slotNum, aboveTheFold, topPos, leftPos);
var hashedImpressionToken = that.getHashedImpressionToken();
var encodedPayload = encodeURIComponent(payload);
var finalAESPixelUrl = AESPixelUrl + hashedImpressionToken + "/pixel/"+encodedPayload
+ "&cb=" + (new Date()).getTime();
that.generateImage(finalAESPixelUrl);
}
};
that.createViewbilityPayload = function(slotNum, aboveTheFold, topPos, leftPos){
var viewbilityAttr = {};
if(typeof aboveTheFold !== "undefined") viewbilityAttr["above_the_fold"] = aboveTheFold;
if(typeof topPos !== "undefined") viewbilityAttr["topPos"] = topPos;
if(typeof leftPos !== "undefined") viewbilityAttr["leftPos"] = leftPos;
if(typeof slotNum !== "undefined"){
//handling case when only slotnum is passed
if (Object.keys(viewbilityAttr).length === 0)
viewbilityAttr["viewable"] = true;
viewbilityAttr["slotNum"] = slotNum;
}
var stringifiedData = "";
if(typeof amzn_assoc_utils !== "undefined" && typeof amzn_assoc_utils["stringify"] === "function")
stringifiedData = amzn_assoc_utils.stringify({"adViewability":[viewbilityAttr]});
return stringifiedData;
};
that.generateImage = function(imageSrc){
if(typeof imageSrc !== "undefined")
(new Image()).src = imageSrc;
};
that.addABPFlag = function(data, callback) {
var detected = false,
checksRemain = 2,
img1 = document.body ? document.body.appendChild(new Image()) : new Image(),
img2 = document.body ? document.body.appendChild(new Image()) : new Image(),
error1 = false,
error2 = false,
random = Math.random() * 11,
px = ABPPixelURL + "?ch=*&rn=*",
beforeCheck = function(callback, timeout) {
if (checksRemain === 0 || timeout > 1E3) {
data.supplySideMetadata = {
ABPInstalled: checksRemain === 0 && detected
};
callback(data);
} else {
setTimeout(function() {
beforeCheck(callback, timeout * 2);
}, timeout * 2);
}
},
checkImages = function() {
if(--checksRemain)
return;
detected = !error1 && error2;
};
img1.style.display = "none";
img2.style.display = "none";
img1.onload = checkImages;
img1.onerror = function() {
error1 = true;
checkImages();
};
img1.src = px.replace(/\*/, 1).replace(/\*/, random);
img2.onload = checkImages;
img2.onerror = function() {
error2 = true;
checkImages();
};
img2.src = px.replace(/\*/, 2).replace(/\*/, random);
beforeCheck(callback, 250);
};
return that;
};
if(typeof amzn_assoc_utils === "undefined") {
amzn_assoc_utils = {};
}
</head>
<body style="margin-bottom: 0px; margin-top: 0px;" class="vsc-initialized" marginwidth="0">
<div id="amznBanners_assoc_banner_placement_default_${slotNum}_div">
<img id="amznBanners_assoc_banner_placement_default_${slotNum}_img" usemap="#amznBanners_assoc_banner_placement_default_${slotNum}_boxmap" src="https://images-na.ssl-images-amazon.com/images/G/15/img15/biss/Associates/24569-CA-BISS-21Aug-frassco_160x600._V313078032_.png">
<map name="amznBanners_assoc_banner_placement_default_${slotNum}_boxmap">
<area id="amznBanners_assoc_banner_placement_default_${slotNum}_privacybox" shape="rect" coords="(0,588,160,600)" href="http://rcm-na.amazon-adsystem.com/e/cm/privacy-policy.html?o=15" target="_top" rel="nofollow">
<area id="amznBanners_assoc_banner_placement_default_${slotNum}_a" shape="rect" coords="0,0,10000,10000" href="https://www.amazon.ca/b?tag=suddenlysas06-20&linkCode=ur1&node=11076213011" target="_top" rel="nofollow">
</map>
</div>
<script type="text/javascript">
amzn_assoc_ad_spec.isIframe = true;
amzn_assoc_ad_spec.linkCode = "ur1";
window.amznBannerAd(amzn_assoc_ad_spec).init();
var amazon_assoc_ir_f_call_associates_ads = function(map) {
var logTypeStr = "", foresterURL, json;
if(typeof JSON !== 'undefined') json = JSON.stringify(map);
else if(typeof amzn_assoc_utils !== 'undefined') json = amzn_assoc_utils.stringify(map);
else return;
if(typeof map.logType !== "undefined") logTypeStr = "&logType=" + map.logType;
// forester URLs are of format //<end_point>/<api_version>/<channel_id>/<channel_version>/<OPERATION>/
// Depending on operation, we either pass the data in the URI or we pass them as query parameters
// if operation is OP, data must be in query parameters while if operation is TOP,
// data must be in the URI itself
foresterURL = "//fls-na.amazon-adsystem.com/1/associates-ads/1/OP/r/json";
foresterURL = foresterURL + "?cb=" + (new Date()).getTime() + logTypeStr + "&p=" + encodeURIComponent(json);
(new Image()).src = foresterURL;
};
var amazon_assoc_ir_f_call = amazon_assoc_ir_f_call_associates_ads;
</script>
</body></iframe>
注意:这不会检测到普通的可见性隐藏(他们使用注入样式使它们不可见而不是阻塞和折叠)或更复杂的阻塞,如果(可能是“何时”)最终会发生这演变成一场(反)广告拦截器军备竞赛。这是一场你赢不了的比赛,而且可能会激怒你的用户。只是对它“友善”应该可以避免这种情况,选择大部分“不引人注目”的基于文本的广告并通过电子邮件向广告拦截器团队发送电子邮件以将您列入不引人注目的列表是另一种选择。
但是,我强调这一点,这是你的决定。
我的功能广告拦截器
const _handleNavigation = async () => {
dispatch('RESET_CONTEXT');
try {
const url = `https://ads.google.com?=${new Date().getTime()}`;
await axios.get(url);
router.push('/post');
} catch (error) {
enqueueSnackbar(`Please disable your ad blocker to post`, snackbar.ERROR_TOP_CENTER);
}
};