이 가이드는 Google 모바일 광고 Android SDK를 사용하여 앱 오프닝 광고를 통합하려는 게시자를 대상으로 작성되었습니다.
앱 오프닝 광고는 앱 로드 화면으로 수익을 올리려는 게시자를 위한 특별한 광고 형식입니다. 앱 오프닝 광고는 언제든 닫을 수 있으며 사용자가 앱을 포그라운드로 가져올 때 표시되도록 설계되었습니다.
앱 오프닝 광고는 사용자가 앱을 사용 중임을 알 수 있도록 작은 브랜딩 영역을 자동으로 표시합니다. 앱 오프닝 광고는 다음과 같이 게재됩니다.
크게 다음과 같은 주요 단계가 있습니다.
Application
클래스를 확장하여 GMA SDK를 초기화합니다.- 광고를 표시하기 전에 광고를 로드하는 유틸리티 클래스를 생성합니다.
- 광고를 로드합니다.
ActivityLifecycleCallbacks.
를 수신합니다.- 광고를 표시하고 콜백을 처리합니다.
- 포그라운드 이벤트 도중 광고를 표시할 수 있도록
LifecycleObserver
인터페이스를 구현하고 등록합니다.
기본 요건
- Google 모바일 광고 SDK 19.4.0 이상
- 시작 가이드의 설정 안내를 따릅니다.
항상 테스트 광고로 테스트
앱을 제작하고 테스트할 때 운영 중인 실제 광고가 아닌 테스트 광고를 사용하세요. 이렇게 하지 않으면 계정이 정지될 수 있습니다.
테스트 광고를 로드하는 가장 쉬운 방법은 앱 오프닝 광고 전용 테스트 광고 단위 ID를 사용하는 것입니다.
ca-app-pub-3940256099942544/3419835294
이 ID는 모든 요청에 대해 테스트 광고를 반환하도록 특별히 구성되었으며, 코딩, 테스트, 디버깅 중에 앱에서 자유롭게 사용할 수 있습니다. 앱을 게시하기 전에 이 ID를 자체 광고 단위 ID로 바꿔야 합니다.
모바일 광고 SDK의 테스트 광고가 작동하는 방식을 자세히 알아보려면 테스트 광고를 참고하세요.
Application 클래스 확장
MyApplication
이라는 새 클래스를 만들고 다음 코드를 추가합니다.
package com.google.android.gms.example.appopendemo;
import android.app.Application;
import com.google.android.gms.ads.MobileAds;
import com.google.android.gms.ads.initialization.InitializationStatus;
import com.google.android.gms.ads.initialization.OnInitializationCompleteListener;
/** The Application class that manages AppOpenManager. */
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
MobileAds.initialize(
this,
new OnInitializationCompleteListener() {
@Override
public void onInitializationComplete(InitializationStatus initializationStatus) {}
});
}
}
이렇게 하면 SDK가 초기화되고 나중에 앱 포그라운드 이벤트에 등록할 수 있는 스켈레톤이 제공됩니다.
다음으로 AndroidManifest.xml
에 아래의 코드를 추가합니다.
<application
android:name="com.google.android.gms.example.appopendemo.MyApplication" ...>
...
</application>
반드시 실제 패키지 이름을 참조하세요.
유틸리티 클래스 구현
광고는 빠르게 게재되어야 하므로 광고를 게재하기 전에 미리 로드하는 것이 좋습니다. 이렇게 하면 사용자가 앱을 실행하자마자 바로 광고를 게재할 수 있습니다. 광고를 표시해야 하는 시점에 앞서 미리 광고 요청을 할 수 있도록 유틸리티 클래스를 구현합니다.
AppOpenManager
라는 새 클래스를 만들고 다음과 같이 작성합니다.
import static androidx.lifecycle.Lifecycle.Event.ON_START;
import android.app.Activity;
import android.app.Application;
import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.lifecycle.LifecycleObserver;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.OnLifecycleEvent;
import androidx.lifecycle.ProcessLifecycleOwner;
import com.google.android.gms.ads.AdError;
import com.google.android.gms.ads.AdRequest;
import com.google.android.gms.ads.FullScreenContentCallback;
import com.google.android.gms.ads.appopen.AppOpenAd;
import java.util.Date;
/** Prefetches App Open Ads. */
public class AppOpenManager {
private static final String LOG_TAG = "AppOpenManager";
private static final String AD_UNIT_ID = "ca-app-pub-3940256099942544/3419835294";
private AppOpenAd appOpenAd = null;
private AppOpenAd.AppOpenAdLoadCallback loadCallback;
private final MyApplication myApplication;
/** Constructor */
public AppOpenManager(MyApplication myApplication) {
this.myApplication = myApplication;
}
/** Request an ad */
public void fetchAd() {
// We will implement this below.
}
/** Creates and returns ad request. */
private AdRequest getAdRequest() {
return new AdRequest.Builder().build();
}
/** Utility method that checks if ad exists and can be shown. */
public boolean isAdAvailable() {
return appOpenAd != null;
}
}
이 클래스 셸은 로드된 광고,
광고 단위 ID, AppOpenAdLoadCallback
을 추적하는 인스턴스 변수를 관리합니다.
이제 유틸리티 클래스가 있으므로 MyApplication
클래스에서 이 클래스를
인스턴스화할 수 있습니다.
/** The Application class that manages AppOpenManager. */
public class MyApplication extends Application {
private static AppOpenManager appOpenManager;
@Override
public void onCreate() {
super.onCreate();
MobileAds.initialize(
this,
new OnInitializationCompleteListener() {
@Override
public void onInitializationComplete(InitializationStatus initializationStatus) {}
});
appOpenManager = new AppOpenManager(this);
}
}
광고 로드
다음 단계에서는 fetchAd()
메서드를 작성합니다. AppOpenManager
클래스에 다음 코드를
추가합니다.
/** Prefetches App Open Ads and handles lifecycle detection. */
public class AppOpenManager {
...
/** Request an ad */
public void fetchAd() {
// Have unused ad, no need to fetch another.
if (isAdAvailable()) {
return;
}
loadCallback =
new AppOpenAd.AppOpenAdLoadCallback() {
/**
* Called when an app open ad has loaded.
*
* @param ad the loaded app open ad.
*/
@Override
public void onAppOpenAdLoaded(AppOpenAd ad) {
AppOpenManager.this.appOpenAd = ad;
}
/**
* Called when an app open ad has failed to load.
*
* @param loadAdError the error.
*/
@Override
public void onAppOpenAdFailedToLoad(LoadAdError loadAdError) {
// Handle the error.
}
};
AdRequest request = getAdRequest();
AppOpenAd.load(
myApplication, AD_UNIT_ID, request,
AppOpenAd.APP_OPEN_AD_ORIENTATION_PORTRAIT, loadCallback);
}
...
}
AppOpenAdLoadCallback
에는 AppOpenAd
로드가 완료되면 호출되는 메서드가
있습니다.
현재 활동 추적
광고를 표시하려면 Activity
컨텍스트가 필요합니다. 사용자가 이용한
최신 Activity 컨텍스트를 추적하려면 AppOpenManager
클래스에서
Application.ActivityLifecycleCallbacks
인터페이스를 구현하도록 합니다.
...
/** Prefetches App Open Ads and handles lifecycle detection. */
public class AppOpenManager implements Application.ActivityLifecycleCallbacks {
private Activity currentActivity;
...
/** ActivityLifecycleCallback methods */
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {}
@Override
public void onActivityStarted(Activity activity) {
currentActivity = activity;
}
@Override
public void onActivityResumed(Activity activity) {
currentActivity = activity;
}
@Override
public void onActivityStopped(Activity activity) {}
@Override
public void onActivityPaused(Activity activity) {}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle bundle) {}
@Override
public void onActivityDestroyed(Activity activity) {
currentActivity = null;
}
}
현재 활동을 추적하여 광고를 표시하는 데 사용할 수 있는 컨텍스트를
확보합니다. 이제 AppOpenManager
생성자의 registerActivityLifecycleCallbacks Application
메서드를 사용하여
이 인터페이스를 등록해야
합니다.
/** Constructor */
public AppOpenManager(MyApplication myApplication) {
this.myApplication = myApplication;
this.myApplication.registerActivityLifecycleCallbacks(this);
}
registerActivityLifecycleCallbacks
를 사용하면
모든 Activity
이벤트를 수신할 수 있습니다. 활동이 시작되고 소멸될 때를 수신하여
현재 Activity
에 대한 참조를 추적할 수 있고, 이 참조는
앱 오프닝 광고를 표시하는 데 사용됩니다.
광고 표시 및 전체 화면 콜백 이벤트 처리
AppOpenManager
클래스에 다음 메서드를 추가합니다.
/** Prefetches App Open Ads and handles lifecycle detection. */
public class AppOpenManager implements Application.ActivityLifecycleCallbacks {
...
private static boolean isShowingAd = false;
/** Shows the ad if one isn't already showing. */
public void showAdIfAvailable() {
// Only show ad if there is not already an app open ad currently showing
// and an ad is available.
if (!isShowingAd && isAdAvailable()) {
Log.d(LOG_TAG, "Will show ad.");
FullScreenContentCallback fullScreenContentCallback =
new FullScreenContentCallback() {
@Override
public void onAdDismissedFullScreenContent() {
// Set the reference to null so isAdAvailable() returns false.
AppOpenManager.this.appOpenAd = null;
isShowingAd = false;
fetchAd();
}
@Override
public void onAdFailedToShowFullScreenContent(AdError adError) {}
@Override
public void onAdShowedFullScreenContent() {
isShowingAd = true;
}
};
appOpenAd.show(currentActivity, fullScreenContentCallback);
} else {
Log.d(LOG_TAG, "Can not show ad.");
fetchAd();
}
}
...
}
이 메서드는 광고를 표시하며, 이때
광고가 표시되거나 광고 표시가 실패하거나 광고가 닫히는 등의
이벤트를 처리하기 위해 FullScreenContentCallback
익명 클래스를 전달합니다. 사용자가 앱 오프닝 광고를 클릭하여 앱을 떠났다가
돌아올 경우 이 메서드는 해당 사용자에게 다른 앱 오프닝 광고가 표시되지 않도록
합니다.
앱 포그라운드 이벤트 수신
Gradle 파일에 라이브러리 추가
앱 포그라운드 이벤트에 대한 알림을 받으려면 LifecycleObserver
를
등록해야 합니다. 먼저 LifecycleObserver
라이브러리를 포함하도록
애플리케이션 수준의 build.gradle
파일을 수정합니다.
apply plugin: 'com.android.application'
android {
compileSdkVersion 28
buildToolsVersion "29.0.0"
defaultConfig {
applicationId "com.google.android.gms.example.appopendemo"
minSdkVersion 18
targetSdkVersion 28
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation 'androidx.appcompat:appcompat:1.0.2'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'com.google.android.gms:play-services-ads:19.4.0'
def lifecycle_version = "2.0.0"
implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-runtime:$lifecycle_version"
annotationProcessor "androidx.lifecycle:lifecycle-compiler:$lifecycle_version"
}
LifecycleObserver 인터페이스 구현
LifecycleObserver
인터페이스를 구현하여
AppOpenManager
클래스에서 포그라운드 이벤트를 수신할 수 있습니다. 다음을
추가하여 클래스를 수정합니다.
package com.google.android.gms.example.appopendemo;
import static androidx.lifecycle.Lifecycle.Event.ON_START;
import android.app.Activity;
import android.app.Application;
import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.lifecycle.LifecycleObserver;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.OnLifecycleEvent;
import androidx.lifecycle.ProcessLifecycleOwner;
import com.google.android.gms.ads.AdError;
import com.google.android.gms.ads.AdRequest;
import com.google.android.gms.ads.FullScreenContentCallback;
import com.google.android.gms.ads.appopen.AppOpenAd;
import java.util.Date;
/** Prefetches App Open Ads and handles lifecycle detection. */
public class AppOpenManager implements LifecycleObserver, Application.ActivityLifecycleCallbacks {
...
/** Constructor */
public AppOpenManager(MyApplication myApplication) {
this.myApplication = myApplication;
this.myApplication.registerActivityLifecycleCallbacks(this);
ProcessLifecycleOwner.get().getLifecycle().addObserver(this);
}
/** LifecycleObserver methods */
@OnLifecycleEvent(ON_START)
public void onStart() {
showAdIfAvailable();
Log.d(LOG_TAG, "onStart");
}
...
}
LifecycleObserver
를 등록하면 앱 실행 및 포그라운드 이벤트가 앱에 전달되며
적절한 시점에 광고를 표시할 수 있습니다.
광고 만료 고려
만료된 광고가 표시되지 않도록 하려면 AppOpenManager
에 메서드를 추가해
광고 참조가 로드된 후 경과한 시간을 확인합니다. 그런 다음
이 메서드를 사용해 광고가 여전히 유효한지 확인합니다. 다음과 같이
AppOpenManager
메서드를 업데이트합니다.
/** Prefetches App Open Ads and handles lifecycle detection. */
public class AppOpenManager implements LifecycleObserver, Application.ActivityLifecycleCallbacks {
...
private long loadTime = 0;
/** Request an ad */
public void fetchAd() {
// Have unused ad, no need to fetch another.
if (isAdAvailable()) {
return;
}
loadCallback =
new AppOpenAd.AppOpenAdLoadCallback() {
/**
* Called when an app open ad has loaded.
*
* @param ad the loaded app open ad.
*/
@Override
public void onAppOpenAdLoaded(AppOpenAd ad) {
AppOpenManager.this.appOpenAd = ad;
AppOpenManager.this.loadTime = (new Date()).getTime();
}
/**
* Called when an app open ad has failed to load.
*
* @param loadAdError the error.
*/
@Override
public void onAppOpenAdFailedToLoad(LoadAdError loadAdError) {
// Handle the error.
}
};
AdRequest request = getAdRequest();
AppOpenAd.load(
myApplication, AD_UNIT_ID, request, AppOpenAd.APP_OPEN_AD_ORIENTATION_PORTRAIT, loadCallback);
}
...
/** Utility method to check if ad was loaded more than n hours ago. */
private boolean wasLoadTimeLessThanNHoursAgo(long numHours) {
long dateDifference = (new Date()).getTime() - this.loadTime;
long numMilliSecondsPerHour = 3600000;
return (dateDifference < (numMilliSecondsPerHour * numHours));
}
/** Utility method that checks if ad exists and can be shown. */
public boolean isAdAvailable() {
return appOpenAd != null && wasLoadTimeLessThanNHoursAgo(4);
}
}
콜드 스타트 및 로드 화면
지금까지 이 문서에서는 메모리에 일시중지된 상태로 있는 앱을 사용자가 포그라운드로 가져올 때만 앱 오프닝 광고가 게재된다고 가정했습니다. '콜드 스타트'는 앱이 실행되었지만 실행되기 전에 앱이 일시중지 상태로 메모리에 있지 않은 경우 발생합니다.
콜드 스타트의 한 예는 사용자가 앱을 처음으로 열 때입니다. 콜드 스타트 상황에는 미리 로드되어 즉시 표시할 수 있는 앱 오프닝 광고가 없습니다. 광고를 요청하고 광고를 수신하는 시점 사이에 지연 시간이 발생하면 사용자가 잠시 앱을 사용하다가 난데없이 게재되는 광고로 인해 놀라는 상황이 발생할 수 있습니다. 이는 사용자 경험에 악영향을 미치므로 피해야 합니다.
콜드 스타트가 발생할 때 앱 오프닝 광고를 사용하는 바람직한 방법은 게임 또는 앱 애셋을 로드할 때의 로드 화면을 사용하고 해당 로드 화면에서만 광고를 표시하는 것입니다. 앱에서 로드가 완료되고 사용자에게 앱의 주요 콘텐츠를 전송한 후에는 광고를 표시하지 않아야 합니다.
권장사항
앱 오프닝 광고를 사용하면 앱을 처음 실행할 때와 앱을 전환하는 동안 앱의 로드 화면으로 수익을 창출할 수 있지만, 사용자가 앱을 사용하는 데 불편하지 않도록 권장사항을 고려하는 것이 중요합니다. 이러한 권장사항은 다음과 같습니다.
- 사용자가 앱을 몇 번 사용한 후에 처음으로 앱 오프닝 광고를 표시합니다.
- 사용자가 앱이 로드되기를 기다리는 동안 앱 오프닝 광고를 표시합니다.
- 앱 오프닝 광고 아래에 로드 화면이 있고 광고가 사라지기 전에 화면에서
로드가 완료된다면
onAdDismissedFullScreenContent()
메서드로 로드 화면을 닫는 것이 좋습니다.