만족
[React] 애드블록(Adblock) 탐지 hooks 만들기 본문
[React] 애드블록(Adblock) 탐지 hooks 만들기
FrontEnd/React Satisfaction 2022. 1. 29. 23:50애드블록은 브라우저를 사용할 때 표시되는 광고의 로딩을 막아
빠른 로딩이 가능하고 쾌적한 이용을 할 수 있게 해 주는 확장 프로그램이다.
그렇지만 개발자나 운영자 입장에서는 트래픽은 나오는데 수익으로 이어지지 않게 하는 아주 골치아픈 녀석이다.
https://adblockplus.org/ko/faq_internal
애드블록은 브라우저에서 요청을 보낼 때 그 요청 대상이 등록된 광고 관련 주소일 경우
요청을 드랍시키는 방법으로 광고를 차단한다.
애드블록이 차단하는 구글 애드센스
구글 애드센스 역시 애드블록이 차단한다.
<script
async
src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"
></script>
페이지에 애드센스를 등록할 때 html하단에 다음과 같은 코드를 추가한 기억이 있을 것이다.
그런데 애드블록이 켜진 상태에서는 아래와 같이 동작한다
기본 초기화 코드를 불러오는 것 자체를 막고 있기 때문에 광고 표시 기능이 무력화된다.
여기에서 아이디어를 얻어 애드블럭을 감지해 보자
애드블록 차단 감지 아이디어
https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js
로 요청을 보내면 그 요청이 실패한다.
따라서 해당 주소로 요청을 보내고 실패하면 애드블록이 감지한다고 볼 수도 있겠다.
(물론 순간적으로 네트워크 상태가 불안정해진다던지 해서 실패할 수도 있다)
axios를 사용하면
axios
.request({
url: `https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js`
})
.then(res => {
//adblock may be disabled
})
.catch(e => {
//adblock may be enabled
});
위와 같이 애드블록이 작동중인지를 추정해볼 수 있다.
그런데 html과 js모두 adsbygoogle.js를 로드하므로 같은 코드를 두번 로드하고 있다.
html에서 해당 스크립트 코드를 제거하고, js에서 로드해서 적용해 보자.
axios
.request({
url: `https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js`
})
.then(res => {
//adblock may be disabled
eval(res.data);
})
.catch(e => {
//adblock may be enabled
});
eval을 사용해 해당 url에서 로드한 js코드를 실행시킬 수 있다.
해당 작업은 20~30ms정도가 소요된다.
이제 js에서 구글 애드센스 js 코드를 로드하고 차단되었는지 여부까지 확인할 수 있게 됐다.
애드블록 탐지 hooks
import { useEffect, useState } from "react";
import axios from "axios";
let adblockState = undefined;
const useAdblockState = () => {
const [isBlocked, setIsBlocked] = useState(adblockState);
useEffect(() => {
if (adblockState === undefined) {
axios
.request({
url: `https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js`
})
.then(res => {
eval(res.data);
setIsBlocked(false);
})
.catch(e => {
console.error("maybe adblock is enabled", e);
setIsBlocked(true);
});
}
}, []);
useEffect(() => {
if (typeof isBlocked === "boolean") {
adblockState = isBlocked;
}
}, [isBlocked]);
return isBlocked;
};
export default useAdblockState;
앞서 설명했던 로직을 useEffect에 집어넣고, 결과에 따라 isBlocked 상태를 변화시킨다.
hooks 외부에 isBlockedState라는 값을 두었는데, 이것은 애드센스 코드가 중복 로딩되지 않도록 하기 위한 것이다.
이미 성공/실패 여부가 한 번이라도 결정되었다면 더 이상 새로 로딩해서 결과를 갱신할 필요는 없다.
이제 컴포넌트에서 useAdblockState를 사용해 애드블록 탐지를 할 수 있다.
애드블록 탐지 hooks: 중복 로딩 방지와 상태 Sync
만약 App.js에서 ComponentA와 ComponentB가 모두 useAdblockState()를 사용하면 어떻게 될까?
동일한 코드를 두 번 로드하여 eval될 것이다.
이는 의미없이 네트워크 트래픽을 잡아먹는 좋지 않은 작업이다.
import { useEffect, useState } from "react";
import axios from "axios";
//adsense 로딩 여부
let loadingAdsense= false;
let adblockState = undefined;
const useAdblockState = () => {
const [isBlocked, setIsBlocked] = useState(adblockState);
useEffect(() => {
if (loadingAdsense){
//이미 로딩 작업에 들어갔다면 로딩 시도 안함
return;
}
if (adblockState === undefined) {
//adsense 코드 로딩 직전 loadingAdsense= true해줌으로써 중복 로딩 막음
loadingAdsense= true;
axios
.request({
url: `https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js`
})
.then(res => {
eval(res.data);
setIsBlocked(false);
})
.catch(e => {
console.error("maybe adblock is enabled", e);
setIsBlocked(true);
});
}
}, []);
useEffect(() => {
if (typeof isBlocked === "boolean") {
adblockState = isBlocked;
}
}, [isBlocked]);
return isBlocked;
};
export default useAdblockState;
loadingAdsense 변수를 활용하여 애드센스 코드 중복 로딩을 막을 수 있다.
그런데 여전히 ComponentA와 ComponentB가 거의 동시에 삽입되었을 때,
한쪽에서만 로딩이 걸리고 isBlocked가 변경되기 때문에
다른 한쪽에서는 애드블록 활성화 여부를 수신할 수 없게 된다.
따라서 이 때는 전역 상태 관리 도구나 ContextAPI를 이용할 수 있다.
그러나 귀찮기 때문에 setInterval로 adBlockState의 값이 boolean타입으로 변경되었는지를 감시하다가,
값이 할당되면 state를 변경하고 타이머를 해제할 것이다.
import { useEffect, useState } from "react";
import axios from "axios";
//adsense 로딩 여부
let loadingAdsense= false;
let adblockState = undefined;
const useAdblockState = () => {
const [isBlocked, setIsBlocked] = useState(adblockState);
useEffect(() => {
if (loadingAdsense){
//이미 로딩 작업에 들어갔다면 로딩 시도 안함
if (isBlocked === undefined){
//애드블록 상태가 수신되지 않았을 경우 adblockState를 감시하다가
//state(isBlocked)에 반영
//0.1s 단위로 감시한다
const timer= window.setInterval(()=>{
if (typeof adblockState === 'boolean'){
setIsBlocked(adblockState);
//adblockState가 결정되면 타이머 해제
window.clearInterval(timer);
}
}, 100);
//컴포넌트 언마운트시 타이머 해제
return ()=>{
window.clearInterval(timer);
}
}
return;
}
if (adblockState === undefined) {
//adsense 코드 로딩 직전 loadingAdsense= true해줌으로써 중복 로딩 막음
loadingAdsense= true;
axios
.request({
url: `https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js`
})
.then(res => {
eval(res.data);
setIsBlocked(false);
})
.catch(e => {
console.error("maybe adblock is enabled", e);
setIsBlocked(true);
});
}
}, []);
useEffect(() => {
if (typeof isBlocked === "boolean") {
adblockState = isBlocked;
}
}, [isBlocked]);
return isBlocked;
};
export default useAdblockState;
별로 좋은 코드는 아니지만...
어쨌든 이렇게 하면 애드센스 중복 로딩을 막고 애드블록 상태 sync를 할 수 있다.
'FrontEnd > React' 카테고리의 다른 글
[React] Redux-Thunk 를 알아보자 (0) | 2022.03.04 |
---|---|
[React] redux-toolkit 을 알아보자 (0) | 2022.02.25 |
[React] Scss 사용하기 (0) | 2021.12.26 |
[React] react-snap 에서 동적 url 스냅샷에 관한 문제 (0) | 2021.10.12 |
[React] Tooltip 컴포넌트 퍼포먼스 (withStyles 성능 오버헤드) (0) | 2021.08.30 |