Ad Placement API는 웹 또는 앱의 HTML5 게임에 전면 광고와 보상형 광고를 게재하는 애드센스 및 AdMob 개발자를 지원하도록 설계되었습니다. 이 예에서는 Ad Placement API를 게임에 통합하고 이를 사용하여 전면 광고를 게재하는 방법을 알아봅니다.
기본 요건
시작하기 전에 다음 사항이 필요합니다.
- 같은 디렉터리에 빈 파일 두 개를 만듭니다.
- index.html
- game.js
- Python을 로컬 환경에 설치하거나 웹 서버를 사용하여 구현을 테스트합니다.
앱 샘플 코드
AdMob 게시자의 경우 샘플 앱 코드를 다운로드하면 API를 앱 게임에 통합하는 방법을 더 잘 이해할 수 있습니다.
1. 개발 서버 시작하기
Ad Placement API는 로드되는 페이지와 동일한 프로토콜을 통해 종속 항목을 로드하므로 웹 서버를 사용하여 앱을 테스트해야 합니다. Python의 기본 제공 서버를 사용하여 로컬 개발 환경을 만들 수 있습니다.
터미널을 엽니다.
index.html 파일이 있는 디렉터리로 이동한 후 다음을 실행합니다.
python -m http.server 8000
웹브라우저에서
localhost:8000
으로 이동합니다.
Apache HTTP 서버와 같은 기타 웹 서버도 사용할 수 있습니다.
2. HTML5 게임 만들기
index.html
을 수정하여 HTML5 캔버스 요소 및 게임플레이를
트리거하는 버튼을 만듭니다. 그런 다음 필요한 스크립트 태그를 추가하여 game.js
파일을 로드합니다.
index.html
<!doctype html>
<html lang="en">
<head>
<title>Ad Placement API HTML5 demo</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<canvas id="gameContainer" height="300px" width="300px"></canvas>
<br>
<button id="playButton">Play</button>
<button style="display:none" id="headsButton">Heads</button>
<button style="display:none" id="tailsButton">Tails</button>
<script src="game.js"></script>
</body>
</html>
'재생' 버튼을 클릭하여 동전 던지기 게임을 즐길 수 있도록 game.js를 수정합니다.
game.js
// Create a coin flip game
class Game {
constructor() {
// Define variables
this.score = 0;
this.choice = '';
this.canvas = document.getElementById('gameContainer').getContext('2d');
this.canvas.font = '24px Arial';
this.playButton = document.getElementById('playButton');
this.headsButton = document.getElementById('headsButton');
this.tailsButton = document.getElementById('tailsButton');
// On click listeners for the game's buttons.
this.playButton.addEventListener('click', () => {
this.erase();
this.play();
});
this.headsButton.addEventListener('click', () => {
this.choice = 'Heads';
this.flipCoin();
});
this.tailsButton.addEventListener('click', () => {
this.choice = 'Tails';
this.flipCoin();
});
this.erase();
}
// Start the game
play() {
this.score = 0;
this.canvas.fillText('Score: ' + this.score, 8, 26);
this.canvas.fillText('Heads or Tails?', 66, 150);
this.playButton.style.display = 'none';
this.headsButton.style.display = 'inline-block';
this.tailsButton.style.display = 'inline-block';
}
// Flip the coin
flipCoin() {
this.headsButton.disabled = true;
this.tailsButton.disabled = true;
this.erase();
this.canvas.fillText('Score: ' + this.score, 8, 26);
this.canvas.fillText('Flipping coin . . .', 60, 150);
setTimeout(() => { this.coinLanded() }, 2000);
}
// Logic for when the coin lands
coinLanded() {
this.headsButton.disabled = false;
this.tailsButton.disabled = false;
let sideUp;
if(Math.random() < 0.5) {
sideUp = 'Heads';
} else {
sideUp = 'Tails';
}
if (sideUp === this.choice ) {
this.win(sideUp);
} else {
this.lose(sideUp);
}
}
// Guess the flip correctly
win(sideUp) {
this.erase();
this.score += 1;
this.canvas.fillText('Score: ' + this.score, 8, 26);
this.canvas.fillText('It was ' + sideUp + '!', 66, 150);
this.canvas.fillText('Guess again', 70, 200);
}
// Guess the flip incorrectly
lose(sideUp) {
this.erase();
this.canvas.fillText('Sorry, it was ' + sideUp, 50, 100);
this.canvas.fillText('Your score was ' + this.score, 50, 150);
this.canvas.fillText('Want to play again?', 45, 200);
this.playButton.style.display = 'inline-block';
this.headsButton.style.display = 'none';
this.tailsButton.style.display = 'none';
}
// Erase the canvas
erase() {
this.canvas.fillStyle = '#ADD8E6';
this.canvas.fillRect(0, 0, 300, 300);
this.canvas.fillStyle = '#000000';
}
}
const game = new Game();
이 단계를 완료하면 브라우저에서 index.html
을 열 때(개발 서버를 통해)
게임 캔버스와 '재생' 버튼이 표시됩니다.
재생을 클릭하면 동전 던지기 게임이 시작됩니다.
3. Ad Placement API 가져오기
다음으로 game.js
의 태그 앞 index.html
에 스크립트 태그를 삽입해
게임에 Ad Placement API를 추가합니다.
스크립트 태그는 여러 매개변수를 사용할 수 있습니다. 다음 매개변수를 사용하여 애드센스 속성 코드를 지정하고 테스트 모드를 사용 설정합니다.
data-ad-client=<AdSense property code>
애드센스 속성 코드입니다. 이는 앱 내에서 실행되는 게임에서도 항상 필요합니다.data-adbreak-test="on"
테스트 모드를 사용 설정합니다. 플레이어에게 제시된 후에는 게임에서 이 속성을 삭제하세요.
애드센스 코드 설정 및 테스트 모드 사용 설정하기
Ad Placement API 기능은 애드센스 코드에 포함되어 있습니다. 이 기능을 사용하려면
먼저 애드센스 코드를 추가하고 두 가지 주요 함수, 즉 adBreak()
및 adConfig()
를 초기화하는
작은 스크립트 스니펫을 포함해야 합니다.
index.html(웹)
[...]
<canvas id="gameContainer" height="300px" width="300px"></canvas>
<br>
<button id="playButton">Play</button>
<button style="display:none" id="headsButton">Heads</button>
<button style="display:none" id="tailsButton">Tails</button>
<script async
data-adbreak-test="on"
src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-123456789"
crossorigin="anonymous">
</script>
<script>
window.adsbygoogle = window.adsbygoogle || [];
const adBreak = adConfig = function(o) {adsbygoogle.push(o);}
</script>
<script src="game.js"></script>
</body>
</html>
게임 삽입(선택사항)
iframe 내부의 다른 페이지에 게임을 삽입하려 하고 adsbygoogle
태그가 게임의 HTML 페이지에 있는 경우 iframe 요소에 allow='autoplay'
를 추가해야 합니다. 이는 특정 광고를 게임에 게재하는 데 필요한 권장사항입니다.
<head>
<!-- The adsbygoogle tag is not here -->
</head>
<body>
<iframe src="https://www.my-game.com" title="My game" allow="autoplay">
<!-- The game is loaded here and contains the adsbygoogle tag -->
</iframe>
</body>
모바일 앱 지원
H5 게임은 일반 웹브라우저, WebView
, 또는 앱 내의 Chrome 맞춤 탭에서 실행할 수 있습니다. Ad Placement API는 게임이 실행 중인 환경을 감지하고 광고 요청을 적절하게 전달할 수 있습니다. 게임이 일반 웹브라우저에서 실행되는 경우 광고 요청은 일반적인 애드센스 요청으로 간주됩니다. Ad Placement API는 인앱 환경을 감지하면 Google 모바일 광고 SDK(있는 경우)와 통신하여 AdMob 광고를 요청하고 표시합니다.
이 기능은 Google 모바일 광고 SDK에 연결된 Android 앱에서 지원됩니다. 이 기능을 사용 설정하려면 Google 모바일 광고 SDK로 게임을 표시할 WebView
를 등록한 다음 AdMob 광고 단위를 구성하고 이를 애드센스 태그에 추가 매개변수로 전달해야 합니다. 게임이 적절한 앱 내에서 실행되면 Ad Placement API가 이러한 광고 단위를 사용하여 광고를 표시합니다.
모바일 지원을 사용 설정하려면 다음과 같은 추가 태그 매개변수를 지정해야 합니다.
data-admob-interstitial-slot=<AdMob slot ID>
이전에 구성한 AdMob 전면 광고 단위 ID입니다.data-admob-rewarded-slot=<AdMob slot ID>
AdMob 보상형 광고 단위 ID입니다.
애드센스 속성 코드는 항상
data-ad-client
매개변수를 통해 전달되어야 하며, data-admob-interstitial-slot
또는
data-admob-rewarded-slot
중 하나 이상을 지정해야 합니다. 게임에서 두 형식을 모두 사용하는 경우 두 매개변수를 모두 지정해야 합니다.
선택적으로 data-admob-ads-only=on
태그 매개변수를 지정하여 게임에서 AdMob의 광고만 표시하고 AdMob 요청을 지원하지 않는 환경(예: 앱 이외의 환경 또는 Google 모바일 광고 SDK가 구성되지 않은 앱)에서 게임이 플레이되는 경우 애드센스로 대체하지 않아야 함을 나타낼 수도 있습니다.
중요: 게임이 앱 내에 삽입되도록 설계하고자 할 때 앱을 소유하고 있거나 앱 소유자와 수익 배분 계약을 체결할 때 정책을 준수하면서 실적을 높일 수 있는 유일한 방법은 이 AdMob 지원을 사용하는 것입니다.
먼저 Google 모바일 광고 SDK로 게임을 보여 주는 WebView
를 등록합니다.
MainActivity.java(앱)
기본 WebView
설정은 광고에 최적화되어 있지 않습니다. 사용
WebSettings
드림
다음을 위해 WebView
를 구성하는 API:
- 자바스크립트
- 로컬 저장소 액세스
자동 동영상 재생
자바
import android.webkit.CookieManager;
import android.webkit.WebView;
public class MainActivity extends AppCompatActivity {
private WebView webView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
webView = findViewById(R.id.webview);
// Let the web view accept third-party cookies.
CookieManager.getInstance().setAcceptThirdPartyCookies(webView, true);
// Let the web view use JavaScript.
webView.getSettings().setJavaScriptEnabled(true);
// Let the web view access local storage.
webView.getSettings().setDomStorageEnabled(true);
// Let HTML videos play automatically.
webView.getSettings().setMediaPlaybackRequiresUserGesture(false);
// Set the H5AdsWebViewClient.
h5AdsWebViewClient = new H5AdsWebViewClient(this, webView);
webView.setWebViewClient(h5AdsWebViewClient);
h5AdsWebViewClient.setDelegateWebViewClient(pubWebViewClient);
// Register the web view.
MobileAds.registerWebView(webView);
}
}
Kotlin
import android.webkit.CookieManager
import android.webkit.WebView
class MainActivity : AppCompatActivity() {
lateinit var webView: WebView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
webView = findViewById(R.id.webview)
// Let the web view accept third-party cookies.
CookieManager.getInstance().setAcceptThirdPartyCookies(webView, true)
// Let the web view use JavaScript.
webView.settings.javaScriptEnabled = true
// Let the web view access local storage.
webView.settings.domStorageEnabled = true
// Let HTML videos play automatically.
webView.settings.mediaPlaybackRequiresUserGesture = false
// Set the H5AdsWebViewClient.
val h5AdsWebViewClient = H5AdsWebViewClient(this, webView)
webView.webViewClient = h5AdsWebViewClient
h5AdsWebViewClient.delegateWebViewClient = pubWebViewClient
// Register the web view.
MobileAds.registerWebView(webView)
}
}
그런 다음 아래와 같이 AdMob 광고 단위(전면 광고용 1개와 보상형 광고용 1개)를 전달합니다.
index.html(앱)
[...]
<canvas id="gameContainer" height="300px" width="300px"></canvas>
<br>
<button id="playButton">Play</button>
<button style="display:none" id="headsButton">Heads</button>
<button style="display:none" id="tailsButton">Tails</button>
<script async
data-admob-interstitial-slot="ca-app-pub-0987654321/1234567890"
data-admob-rewarded-slot="ca-app-pub-0987654321/0987654321"
src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-123456789"
crossorigin="anonymous">
</script>
<script>
window.adsbygoogle = window.adsbygoogle || [];
const adBreak = adConfig = function(o) {adsbygoogle.push(o);}
</script>
<script src="game.js"></script>
</body>
</html>
4. adConfig() 호출하기
adConfig()
호출은 게임의 현재 구성을 Ad
Placement API에 전달합니다. 이후 API는 이러한 정보를 사용하여 요청하는 광고 유형을
게임에 적합하도록 필터링합니다(예: 사운드가 사용 설정된 경우
사운드가 필요한 동영상 광고로 필터링).
언제든지 구성이 변경되면
(예: 사용자가 게임을 음소거하거나 음소거를 해제하는 경우) adConfig()
가 호출됩니다. 게임의 생성자에서
adConfig()
를 호출한 다음, 게임에 음소거 및 음소거 해제 버튼을 추가하여 추가적으로 adConfig()
를 호출하도록 합니다.
game.js
class Game {
constructor() {
// Define variables
this.score = 0;
this.choice = '';
this.muted = false;
this.canvas = document.getElementById('gameContainer').getContext('2d');
this.canvas.font = '24px Arial';
this.playButton = document.getElementById('playButton');
this.headsButton = document.getElementById('headsButton');
this.tailsButton = document.getElementById('tailsButton');
this.muteButton = document.getElementById('muteButton');
adConfig({
sound: 'on',
});
// On click listeners for the game's buttons.
this.playButton.addEventListener('click', () => {
this.erase();
this.play();
});
this.headsButton.addEventListener('click', () => {
this.choice = 'Heads';
this.flipCoin();
});
this.tailsButton.addEventListener('click', () => {
this.choice = 'Tails';
this.flipCoin();
});
this.muteButton.addEventListener('click', () => {
var soundString = this.muted ? 'on' : 'off';
this.muteButton.innerHTML = this.muted ? 'Mute sound' : 'Un-mute sound';
this.muted = !this.muted;
adConfig({
sound: soundString,
});
});
this.erase();
[...]
이제 HTML 파일에 음소거 버튼을 추가합니다.
index.html
[...]
<canvas id="gameContainer" height="300px" width="300px"></canvas>
<br>
<button id="playButton">Play</button>
<button style="display:none" id="headsButton">Heads</button>
<button style="display:none" id="tailsButton">Tails</button>
<button id="muteButton">Mute sound</button>
<script async
data-adbreak-test="on"
src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-123456789"
crossorigin="anonymous">
</script>
[...]
5. 게임 종료 시 adBreak()
호출하기
adBreak()
호출은 광고 게재위치를 정의하며, 게임의 해당 지점에서
광고를 게재하는 데 필요한 모든 것을 지정하는 게재위치 구성이라는 객체를
취합니다. 다양한 유형의 광고를 지원하려면 게재위치 구성의 여러
하위 집합을 초기화해야 합니다.
adBreak()
호출은 광고를 게재할 수 있는 위치인 게재위치, 즉 광고를 게재할 수 있는
기회를 정의합니다. 광고가 실제로 표시되는지 여부는 다음과 같은
여러 요인에 따라 결정됩니다.
- 선언한 광고 게재위치의 유형
- 광고 게재위치 이전에 적절한 사용자 상호작용이 발생했는지 여부
- 현재 플레이어에게 적합한 광고가 있는지 여부. 예를 들어
- 플레이어에게 관련성이 있는 광고
- 플레이어의 데이터 개인 정보 보호 및 동의 설정과 일치하는 광고
- 사용자가 최근에 본 광고의 개수
- 다음 형태 중 하나로 게임에 대해 구성한 컨트롤 설정
- 태그 내 힌트
- 애드센스 내(참고: 애드센스에서 사용할 수 있는 컨트롤은 시간이 지남에 따라 변경됨)
게임을 다시 시작할 때 표시할 전면 광고에 대한 코드를 추가합니다. 게임이 한 번 실행된 후에만 play()
함수 내에서 adBreak()
를 호출합니다.
adBreak()
는 사용자 작업(예: '재생' 버튼 클릭) 중 일부로 호출되어야 합니다. 그렇지 않으면 API에서 광고를 요청하고 표시할 수 없습니다.
광고 시점 전후에 호출할 함수를 만들어 adBreak()
게재위치 구성에서 사용합니다. beforeAd
및 afterAd
함수는
적합한 광고가 있는 경우에만 호출된다는 점을
잊지 마세요.
game.js
class Game {
constructor() {
// Define variables
this.score = 0;
this.choice = '';
this.muted = false;
this.shouldShowAdOnPlay = false;
[...]
// Start the game
play() {
if (this.shouldShowAdOnPlay) {
this.shouldShowAdOnPlay = false;
adBreak({
type: 'next', // ad shows at start of next level
name: 'restart-game',
beforeAd: () => { this.disableButtons(); }, // You may also want to mute the game's sound.
afterAd: () => { this.enableButtons(); }, // resume the game flow.
});
}
this.score = 0;
this.canvas.fillText('Score: ' + this.score, 8, 26);
this.canvas.fillText('Heads or Tails?', 66, 150);
this.playButton.style.display = 'none'
this.headsButton.style.display = 'inline-block'
this.tailsButton.style.display = 'inline-block'
}
[...]
// Guess the flip incorrectly
lose(sideUp) {
this.erase()
this.canvas.fillText('Sorry, it was ' + sideUp, 50, 100);
this.canvas.fillText('Your score was ' + this.score, 50, 150);
this.canvas.fillText('Want to play again?', 45, 200);
this.playButton.style.display = 'inline-block'
this.headsButton.style.display = 'none'
this.tailsButton.style.display = 'none'
this.shouldShowAdOnPlay = true;
}
[...]
// Erase the canvas
erase() {
this.canvas.fillStyle = '#ADD8E6';
this.canvas.fillRect(0, 0, 300, 300);
this.canvas.fillStyle = '#000000';
}
enableButtons() {
this.playButton.disabled = false;
this.headsButton.disabled = false;
this.tailsButton.disabled = false;
}
disableButtons() {
this.playButton.disabled = true;
this.headsButton.disabled = true;
this.tailsButton.disabled = true;
}
}
const game = new Game();
6. 보상형 광고의 adBreak()
호출하기
게임이 종료되지만 사용자가 새로 시작하는 대신 기존 점수를 다시 살리고자 할 때 표시될 보상형 광고의 코드를 추가합니다. lose()
함수 내에서 adBreak()
를 호출하여 보상형 광고를 사용할 수 있는지 확인합니다. 사용할 수 있으면 사용자에게 리워드(이 경우 부활)를 원하는지 묻는 프롬프트를 표시하고, 사용자가 광고를 보는 데 동의할 경우 해당하는 showAdFn()
을 호출합니다. adViewed
및 adDismissed
콜백을 사용하여 사용자가 보상형 광고를 보거나 건너뛰는 경우 필요한 조치를 구성할 수 있습니다.
보상형 광고를 표시할 때마다 adBreak()
를 새로 호출해야 합니다. 이렇게 하면 이전 광고가 만료되거나 이전 광고를 사용할 수 없는 경우 광고가 새로고침됩니다.
광고를 보려면 showAdFn()
을 직접 사용자 작업의 일부로 호출해야 하며 그렇지 않으면 광고가 표시되지 않을 수도 있습니다.
광고 시점 전후에 호출할 함수를 만들어 adBreak()
게재위치 구성에서 사용합니다. beforeReward
, adViewed
, adDismissed
, beforeAd
및 afterAd
함수는 적합한 광고가 있는 경우에만 호출된다는 점을 잊지 마세요.
game.js
class Game {
constructor() {
// Define variables
this.score = 0;
this.choice = '';
this.muted = false;
this.shouldShowAdOnPlay = false;
this.showRewardedAdFn = null;
this.canvas = document.getElementById('gameContainer').getContext('2d');
this.canvas.font = '24px Arial';
this.playButton = document.getElementById('playButton');
this.headsButton = document.getElementById('headsButton');
this.tailsButton = document.getElementById('tailsButton');
this.muteButton = document.getElementById('muteButton');
this.continueButton = document.getElementById('continueButton');
adConfig({
sound: 'on',
});
// On click listeners for the game's buttons.
this.playButton.addEventListener('click', () => {
this.erase();
this.play();
});
this.headsButton.addEventListener('click', () => {
this.choice = 'Heads';
this.flipCoin();
});
this.tailsButton.addEventListener('click', () => {
this.choice = 'Tails';
this.flipCoin();
});
this.muteButton.addEventListener('click', () => {
var soundString = this.muted ? 'on' : 'off';
this.muteButton.innerHTML = this.muted ? 'Mute sound' : 'Un-mute sound';
this.muted = !this.muted;
adConfig({
sound: soundString,
});
});
this.continueButton.addEventListener('click', () => {
if (this.showRewardedAdFn) {
this.showRewardedAdFn();
}
});
this.erase();
}
// Start the game
play() {
if (this.shouldShowAdOnPlay) {
this.shouldShowAdOnPlay = false;
adBreak({
type: 'next', // ad shows at start of next level
name: 'restart-game',
beforeAd: () => { this.disableButtons(); }, // You may also want to mute the game's sound.
afterAd: () => { this.enableButtons(); }, // resume the game flow.
});
}
this.score = 0;
this.canvas.fillText('Score: ' + this.score, 8, 26);
this.canvas.fillText('Heads or Tails?', 66, 150);
this.playButton.style.display = 'none';
this.continueButton.style.display = 'none';
this.headsButton.style.display = 'inline-block';
this.tailsButton.style.display = 'inline-block';
}
[...]
// Guess the flip incorrectly
lose(sideUp) {
this.erase()
this.canvas.fillText('Sorry, it was ' + sideUp, 50, 100);
this.canvas.fillText('Your score was ' + this.score, 50, 150);
this.canvas.fillText('Want to play again?', 45, 200);
this.playButton.style.display = 'inline-block'
this.headsButton.style.display = 'none'
this.tailsButton.style.display = 'none'
this.shouldShowAdOnPlay = true;
adBreak({
type: 'reward', // rewarded ad
name: 'reward-continue',
beforeReward: (showAdFn) => {
this.showRewardedAdFn = () => { showAdFn(); };
// Rewarded ad available - prompt user for a rewarded ad
this.continueButton.style.display = 'inline-block';
},
beforeAd: () => { this.disableButtons(); }, // You may also want to mute the game's sound.
adDismissed: () => {
this.continueButton.style.display = 'none'; // Hide the reward button and continue lose flow.
},
adViewed: () => { this.continueGame(); }, // Reward granted - continue game at current score.
afterAd: () => { this.enableButtons(); }, // Resume the game flow.
});
}
// Continue gameplay at current score
continueGame() {
this.erase();
this.canvas.fillText('Score: ' + this.score, 8, 26);
this.canvas.fillText('Heads or Tails?', 66, 150);
this.playButton.style.display = 'none';
this.continueButton.style.display = 'none';
this.headsButton.style.display = 'inline-block';
this.tailsButton.style.display = 'inline-block';
}
[...]
}
const game = new Game();
이제 HTML 파일에 계속 버튼을 추가합니다.
index.html
[...]
<canvas id="gameContainer" height="300px" width="300px"></canvas>
<br>
<button id="playButton">Play</button>
<button style="display:none" id="headsButton">Heads</button>
<button style="display:none" id="tailsButton">Tails</button>
<button style="display:none" id="continueButton">Watch Ad to continue?</button>
<button id="muteButton">Mute sound</button>
<script async
data-adbreak-test="on"
src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-123456789"
crossorigin="anonymous">
</script>
[...]
이제 동전 던지기 앱은 광고 게재를 위한 광고 게재위치를 만듭니다.
앱에는 게임이 종료될 때 이외에도
광고를 표시할 적절한 추가 위치가 있을 수 있습니다. 이러한 위치에서 adBreak()
를 호출하는 방식도
이 예에 나온 내용과 비슷합니다.
프로덕션 앱 테스트 사용 중지
index.html
의 data-adbreak-test="on"
라인은 해당 코드가 프로덕션에서 테스트 설정을 활성화하므로 앱 출시 전에 삭제하거나 주석 처리해야 합니다.