앱 시작과 함께 광고를 보여주려면? - 애드몹 앱 오프닝 광고
이 글에서 소개하는 앱 오프닝 광고에 대한 자세한 내용은 AdMob On Air 에서 영상으로도 시청하실 수 있습니다.
특히, 아래에 소개되는 예제 코드를 사용하여 앱 오프닝 광고를 앱에 통합하는 과정을 자세히 다루고 있으니, 자세한 과정이 궁금하신 분들은 영상을 꼭 시청해주세요!
사용자가 앱을 사용하려면 반드시 거치는 단계는 무엇일까요? 어떻게 보면 당연한(?) 이야기겠지만, 바로 앱 실행 단계입니다. 사용자 특성에 따라 도달률이 달라지는 다른 단계와는 달리, 앱 실행 단계는 앱을 실행할 때마다 반드시 거치게 됩니다.
앱 수익화 관점에서 이 단계를 평가한다면, 이는 사용자 도달률과 노출률이 모두 높은 지면이기에 매우 높은 가치를 부여할 수 있을 것입니다. 그렇다면, 어떻게 해야 이 지면을 통해 수익을 얻을 수 있을까요? 여러 방법이 있겠지만, 이번에 애드몹에서 오픈 베타로 출시된 앱 오프닝 광고를 사용하면 광고를 통해 추가 수익을 창출할 수 있습니다.
앱 오프닝 광고란?
앱 오프닝 광고 (App Open Ads)는 앱이 실행되는 시점에 표시할 수 있는 광고 포맷으로, 앱이 실행된 후 표시되는 로고 화면 (스플래시) 혹은 로딩 화면 등에 노출할 수 있습니다. 다음은 앱 오프닝 광고의 권장되는 구현 예를 보여줍니다.
가이드라인
권장되는 구현 방식
앞서 본 영상을 단계별로 요약하면 다음과 같습니다.
- 홈 스크린에서 앱 실행
- 스플래시/로딩 화면 표시
- 스플래시/로딩 화면 위에 앱 오프닝 광고 표시
- 광고를 닫은 후, 스플래시 화면이 종료되면서 메인 화면으로 이동
앱 오프닝 광고를 구현할 때 가장 유의해야 하는 단계는 3번 단계로, 광고 뒷 배경에 스플래시/로딩 화면이 유지되는지 꼭 확인해야 합니다.
앱 실행 시점과 더불어, 사용자가 기존에 사용하던 앱으로 복귀하는 시점에도 앱 오프닝 광고를 보여줄 수 있습니다. 다음은 사용중이던 앱으로 복귀하는 시점에 앱 오프닝 광고를 보여주는 사례를 보여줍니다.
권장하지 않는 구현 방식
가이드라인에서 권장하지 않는 구현 사례도 몇 가지 살펴보도록 하겠습니다.
- 앱 오프닝 광고 배경에 아무런 컨텐츠가 표시되지 않는 경우: 광고가 표시되기 직전에 보였던 화면이 그대로 유지되지 않았습니다.
- 앱 오프닝 광고가 앱 컨텐츠 화면이 노출된 이후에 표시되는 경우: 앱 오프닝 광고는 사용자가 앱과 상호작용을 할 수 있는 시점 이전에만 노출해야 합니다.
구현 전에 참고할 사항
광고 노출 관련
여타 포맷과 마찬가지로, 앱 오프닝 광고도 광고를 보여주려면 사전에 광고를 불러온 상태여야 합니다. 따라서, 다음과 같은 경우에는 광고를 노출할 수 없습니다.
- 앱 설치 후 최초로 실행하는 경우
- 광고를 미리 불러온 상태에서 백그라운드 상태로 전환된 앱이 완전히 종료 (메모리에서 제거)된 후 다시 시작되는 경우
- 앱이 완전히 종료될 때, 광고 또한 메모리에서 함께 제거됩니다
- 광고가 더이상 유효하지 않은 경우
- 광고 요청 후 4시간1이 지난 광고는 무효화 됩니다. 따라서 이 경우 캐싱된 광고를 보여주는 대신 새 광고를 요청해야 합니다.
마지막 항목 (광고 유효시간)에서 확인할 수 있듯이, 사용자가 마지막으로 앱을 실행한 후 4시간 이내에 앱을 다시 실행해야만 앱 오프닝 광고를 정상적으로 표시할 수 있습니다. 따라서 사용자가 짧은 주기로 앱을 실행하는 앱 (예: 방치형 게임 등)에서 사용해야 최대의 효과를 발휘할 수 있습니다.
앱 브랜딩 영역
앱이 구글 플레이/앱스토어에 등록되어 있다면 앱 설치 광고 상단에 앱 이름 및 아이콘이 다음과 같이 자동으로 표시됩니다.
단, 앱이 아직 스토어에 등록되지 않았거나 패키지 이름이 스토어에 등록된 이름과 다른 경우 다음과 같이 앱 이름이나 아이콘이 표시되지 않습니다. 앱을 스토어에 등록하지 않는 한, 이를 수동으로 설정할 수 있는 방법은 아직 없습니다.
앱 오프닝 광고 구현하기 (안드로이드)
안드로이드에서 앱 오프닝 광고를 구현하는 방법을 살펴보겠습니다. 만들어볼 예제 앱은 액티비티 두개로 구성되어 있으며, 각 액티비티에서 앱 오프닝 광고를 노출하게 구성되어 있습니다.
Google Mobile Ads SDK 추가
앱 오프닝 광고를 사용하려면 Google Mobile Ads (GMA) SDK 19.4.0 이상 버전을 사용해야 합니다. app/build.gradle
를 연 후, dependencies
섹션을 다음과 같이 변경합니다.
[app/build.gradle]
apply plugin: 'com.android.application'
android {
...
}
dependencies {
...
// Google Mobile Ads SDK를 추가합니다.
implementation "com.google.android.gms:play-services-ads:19.4.0"
}
애드몹 애플리케이션 ID 설정
GMA SDK를 사용하려면 앱 매니페스트(AndroidManifest.xml
)에 자신의 앱의 애드몹 앱 ID (ca-app-pub-xxxx/yyyy
형태)를 추가해야 합니다. 아래는 애드몹 테스트 앱 ID를 매니페스트에 추가한 예를 보여줍니다.
<?xml version="1.0" encoding="utf-8"?>
<manifest>
<application>
...
<!-- 애드몹 앱 ID 추가-->
<meta-data
android:name="com.google.android.gms.ads.APPLICATION_ID"
android:value="ca-app-pub-3940256099942544~3347511713" />
</application>
</manifest>
AppOpenAdManager 클래스 작성
앱 오프닝 광고를 쉽게 제어할 수 있도록 AppOpenAdManager
유틸리티 클래스를 작성합니다. 유틸리티 클래스에서 작성할 메서드는 다음과 같습니다.
showAdIfAvailable()
: 사용할 수 있는 앱 오프닝 광고가 있는 경우 광고를 표시합니다.fetchAd()
: 앱 오프닝 광고를 불러옵니다.isAdAvailable()
: 사용 가능한 (캐시되어 있고 유효한) 앱 오프닝 광고가 있는지 확인합니다.isAdExpired()
: 캐시되어 있는 앱 오프닝 광고가 만료되었는지 확인합니다.
메서드를 구현하기에 앞서, 클래스 내에서 사용할 필드를 정의한 후 생성자를 구현합니다.
public class AppOpenAdManager {
private static final String TAG = "AppOpenManager";
public static final String AD_UNIT_ID = "ca-app-pub-3940256099942544/1033173712";
public static final long AD_EXPIRY_DURATION = 3600000 * 4;
private final Application application;
private Activity mostCurrentActivity;
private AppOpenAd ad;
private boolean isShowingAd = false;
private long lastAdFetchTime = 0L;
public AppOpenAdManager(@NonNull Application application) {
this.application = application;
}
...
}
각 필드의 용도는 다음과 같습니다.
AD_UNIT_ID
: 앱 오프닝 광고의 광고 단위 ID 입니다. (위에 표시된 ID는 테스트 광고 단위입니다)AD_EXPIRY_DURATION
: 광고의 유효 시간을 밀리초 (ms)로 표현한 수치로, 4시간으로 설정되어 있습니다.application
: 애플리케이션 인스턴스를 참조하기 위해 사용합니다. (자세한 내용은 이후 단계에서 별도 설명)mostCurrentActivity
: 가장 최근에 실행된 액티비티를 참조하기 위해 사용합니다. (자세한 내용은 이후 단계에서 별도 설명)ad
: 앱 오프닝 광고 인스턴스로, 미리 불러온 광고를 저장하는 데 사용합니다.isShowingAd
: 앱 오프닝 광고가 현재 노출되고 있는 중인지 상태를 저장합니다.lastAdFetchTime
: 앱 오프닝 광고를 마지막으로 받아온 시간을 저장하며, 광고 만료 여부를 확인할 때 사용합니다.
다음으로, 메서드 AppOpenAdManager
클래스에서 구현할 메서드를 정의합니다. 각 메서드의 몸체는 이후 단계에서 구현하므로 이 단계에서는 큰 틀을 만들어 주기만 합니다.
private boolean isAdExpired() {
// TODO: Implement method
return false;
}
private boolean isAdAvailable() {
// TODO: Implement method
return false;
}
private void fetchAd() {
// TODO: Implement method
}
public void showAdIfAvailable(@Nullable final FullScreenContentCallback listener) {
// TODO: Implement method
}
먼저 isAdExpired()
와 isAdAvailable()
메서드를 다음과 같이 구현합니다. isAdExpired()
메서드는 불러온 광고의 만료 여부를 확인하며, isAdAvailable()
은 현재 불러온 앱 설치가 있는지, 또한 이 광고가 아직 유효한지 확인합니다.
private boolean isAdExpired() {
return System.currentTimeMillis() - lastAdFetchTime > AD_EXPIRY_DURATION;
}
private boolean isAdAvailable() {
return this.ad != null && !isAdExpired();
}
다음, 앱 오프닝 광고 요청에 대한 응답을 처리할 수 있도록 AppOpenAdManager
클래스에 콜백을 구현합니다.
다음과 같이 AppOpenAdManager
가 AppOpenAd.AppOpenAdLoadCallback
을 상속하게 변경한 후, onAppOpenAdLoaded()
및 onAppOpenAdFailedToLoad()
콜백 메서드를 구현합니다.
public class AppOpenAdManager2 extends AppOpenAd.AppOpenAdLoadCallback {
...
// AppOpenAd.AppOpenAdLoadCallback implementations
@Override
public void onAppOpenAdLoaded(AppOpenAd ad) {
Log.d(TAG, "Ad loaded");
this.lastAdFetchTime = System.currentTimeMillis();
this.ad = ad;
}
@Override
public void onAppOpenAdFailedToLoad(LoadAdError error) {
Log.d(TAG, "Failed to load an ad: " + error.getMessage());
}
}
콜백 구현이 완료되었다면 fetchAd()
메서드를 구현합니다. isAvailable()
메서드를 사용하여 이미 사용할 수 있는 광고가 있다면 추가로 로드를 하지 않고, 그렇지 않은 경우에는 AppOpenAd.load()
메서드를 사용하여 앱 오프닝 광고를 로드합니다. 앱 오프닝 광고는 세로 화면 (AppOpenAd.APP_OPEN_AD_ORIENTATION_PORTRAIT
)과 가로 화면 (AppOpenAd.APP_OPEN_AD_ORIENTATION_LANDSCAPE
)을 모두 지원하므로, 원하는 레이아웃에 맞게 광고를 요청할 수 있습니다.
private void fetchAd() {
if (isAdAvailable()) {
return;
}
AdRequest request = new AdRequest.Builder().build();
AppOpenAd.load(application, AD_UNIT_ID,
request, AppOpenAd.APP_OPEN_AD_ORIENTATION_PORTRAIT, this);
}
다음으로 앱 오프닝 광고를 보여주는 메서드인 showAdIfAvailable()
를 구현합니다. 현재 광고가 표시되고 있는 상태이거나 보여줄 수 있는 광고가 없는 경우에는 광고를 표시하지 않습니다. 또한, FulScreenContentCallback
파라미터를 제공하는 경우 앱 오프닝 광고의 표시 상태에 대한 콜백을 받을 수 있게끔 구성되어 있습니다.
앱 오프닝 광고는 AppOpenAd.show()
메서드를 사용하면 앱 오프닝 광고를 표시할 수 있습니다. 앱 오프닝 광고를 표시하려면 액티비티가 필요한데, 이 예제에서는 앱 내에서 가장 최근에 표시된 (즉, 활성 상태인) 액티비티 정보를 사용하여 광고를 표시하는 것을 확인할 수 있습니다.
추가로, FullScreenContentCallback
를 인자로 받지 않는 경우를 위해 아무 파라미터를 받지 않는 버전의 메서드도 함께 추가합니다.
public void showAdIfAvailable(@Nullable final FullScreenContentCallback listener) {
if (this.isShowingAd) {
Log.e(TAG, "Can't show the ad: Already showing the ad");
return;
}
if (!isAdAvailable()) {
Log.d(TAG, "Can't show the ad: Ad not available");
fetchAd();
return;
}
FullScreenContentCallback callback = new FullScreenContentCallback() {
@Override
public void onAdFailedToShowFullScreenContent(AdError error) {
if (listener != null) {
listener.onAdFailedToShowFullScreenContent(error);
}
}
@Override
public void onAdShowedFullScreenContent() {
if (listener != null) {
listener.onAdShowedFullScreenContent();
}
AppOpenAdManager.this.isShowingAd = true;
}
@Override
public void onAdDismissedFullScreenContent() {
if (listener != null) {
listener.onAdDismissedFullScreenContent();
}
isShowingAd = false;
AppOpenAdManager.this.ad = null;
fetchAd();
}
};
ad.show(mostCurrentActivity, callback);
}
public void showAdIfAvailable() {
showAdIfAvailable(null);
}
앱 설치 광고를 표시하기 위해 필요한 액티비티 정보는 얻으려면 ActivityLifecycleCallbacks
인터페이스를 구현해야 합니다. 다음과 같이 AppOpenAdManager
클래스에 Application.ActivityLifecycleCallbacks
를 구현합니다.
가장 최근에 활성화 되어있는 액티비티의 정보를 추적하기 위해, onActivityResumed()
콜백 메서드를 통해 얻은 액티비티의 인스턴스를 mostCurrentActivity
인스턴스에 저장합니다.
public class AppOpenAdManager extends AppOpenAd.AppOpenAdLoadCallback
implements Application.ActivityLifecycleCallbacks {
// Application.ActivityLifecycleCallbacks implementations
@Override
public void onActivityCreated(@NonNull Activity activity, @Nullable Bundle savedInstanceState) {
// Do nothing
}
@Override
public void onActivityStarted(@NonNull Activity activity) {
// Do nothing
}
@Override
public void onActivityResumed(@NonNull Activity activity) {
this.mostCurrentActivity = activity;
}
@Override
public void onActivityPaused(@NonNull Activity activity) {
// Do nothing
}
@Override
public void onActivityStopped(@NonNull Activity activity) {
// Do nothing
}
@Override
public void onActivitySaveInstanceState(@NonNull Activity activity, @NonNull Bundle outState) {
// Do nothing
}
@Override
public void onActivityDestroyed(@NonNull Activity activity) {
// Do nothing
}
}
커스텀 Application 클래스 작성
AppOpenAdManager
는 애플리케이션 레벨에서 작동하므로, 커스텀 애플리케이션 클래스를 작성한 후 AppOpenAdManager
의 인스턴스를 생성해야 합니다.
먼저, 다음과 같이 Application
클래스를 상송하는 커스텀 애플리케이션 클래스를 생성합니다. 아래 예시에서는 MyApplication
이라는 이름으로 클래스를 생성한 예를 보여줍니다.
public class MyApplication extends Application {
}
다음으로, AppOpenAdManager
를 멤버로 추가한 후 onCreate()
에서 인스턴스를 생성합니다. 이 때, MobileAds.initialize()
메서드를 사용하여 SDK 초기화도 함께 수행합니다.
그리고 getAppOpenAdManager()
메서드를 추가하여 앱 내 다른 컴포넌트 (예: 액티비티)에서 AppOpenAdManager
인스턴스를 참조할 수 있도록 합니다.
private AppOpenAdManager appOpenAdManager;
@Override
public void onCreate() {
super.onCreate();
MobileAds.initialize(this);
appOpenAdManager = new AppOpenAdManager(this,
AppOpenAdManager.TEST_AD_UNIT_ID,
AppOpenAd.APP_OPEN_AD_ORIENTATION_PORTRAIT);
}
public AppOpenAdManager getAppOpenAdManager() {
return this.appOpenAdManager;
}
기본 애플리케이션 클래스 대신 커스텀 애플리케이션 클래스를 사용하려면 앱 매니페스트를 수정해야 합니다. AndroidManifest.xml
파일을 연 후, application
태그의 android:name
항목에 앞에서 생성한 커스텀 애플리케이션 클래스를 지정합니다. (아래 예는 MyApplication
클래스가 com.androidhuman.ads.appopenads
패키지에 있는 경우의 예를 보여줍니다)
<?xml version="1.0" encoding="utf-8"?>
<manifest ...>
<application
...
android:name=".MyApplication">
...
</application>
</manifest>
앱 내에 앱 오프닝 광고 추가하기
액티비티 매니페스트 설정 업데이트
구현해볼 예제 애플리케이션은 스플래시 (SplashActivity
)와 메인 (MainActivity
) 두 개의 액티비티로 구성됩니다. 액티비티 클래스를 추가한 후, 스플래시 액티비티가 먼저 실행되도록 다음과 같이 매니페스트를 수정합니다.
<?xml version="1.0" encoding="utf-8"?>
<manifest>
<application>
<!-- SplashActivity를 Launcher 액티비티로 설정합니다 -->
<activity
android:name=".SplashActivity"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".MainActivity"/>
...
</application>
</manifest>
스플래시 액티비티 작성
스플래시 화면에 표시되는 동안 앱 오프닝 광고가 표시될 수 있도록 액티비티 코드를 다음과 같이 작성합니다.
public class SplashActivity extends AppCompatActivity {
private static final String TAG = "SplashActivity";
AppOpenAdManager appOpenAdManager;
private boolean isAdShown = false;
private boolean isAdDismissed = false;
private boolean isLoadCompleted = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash);
appOpenAdManager = ((MyApplication) getApplication()).getAppOpenAdManager();
loadResources();
appOpenAdManager.showAdIfAvailable(new FullScreenContentCallback() {
@Override
public void onAdShowedFullScreenContent() {
isAdShown = true;
}
@Override
public void onAdDismissedFullScreenContent() {
isAdDismissed = true;
if (isLoadCompleted) {
launchMainScreen();
} else {
Log.d(TAG, "Waiting resources to be loaded...");
}
}
});
}
private void loadResources() {
// Wait for 5 seconds
CountDownTimer timer = new CountDownTimer(5000L, 1000L) {
@Override
public void onTick(long millisUntilFinished) {
// Do nothing
}
@Override
public void onFinish() {
isLoadCompleted = true;
// Check whether App Open ad was shown or not.
if (isAdShown) {
// Check App Open ad was dismissed or not.
if (isAdDismissed) {
launchMainScreen();
} else {
Log.d(TAG, "Waiting for ad to be dismissed...");
}
} else {
launchMainScreen();
}
}
};
timer.start();
}
private void launchMainScreen() {
ActivityCompat.finishAffinity(SplashActivity.this);
startActivity(new Intent(SplashActivity.this, MainActivity.class));
}
}
광고가 표시되고 있는 도중에 로드가 완료되는 경우, 바로 다른 화면으로 전환하지 않고 광고가 닫힐 때까지 상태를 유지해야 합니다. loadResources()
메서드와 onCreate()
메서드의 showAdIfAvailable()
메서드 호출부를 보면 광고 표시 여부 및 로드 완료 여부에 따라 화면 전환 여부가 달라지는 것을 확인할 수 있습니다.
메인 액티비티 작성
메인 액티비티에서는 사용자가 메인 액티비티로 복귀했을 때 앱 오프닝 광고를 표시합니다. 메인 화면에 복귀할 때마다 매번 광고를 보여준다면 사용자 경험에 해가 되므로, 예제에서는 세번에 한번 꼴로 광고를 보여주도록 설정했습니다.
public class MainActivity extends AppCompatActivity {
private AppOpenAdManager appOpenAdManager;
private int numActivityRestarted = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
appOpenAdManager = ((MyApplication) getApplication()).getAppOpenAdManager();
}
@Override
protected void onRestart() {
super.onRestart();
numActivityRestarted++;
if (canShowAppOpenAd()) {
appOpenAdManager.showAdIfAvailable();
}
}
private boolean canShowAppOpenAd() {
return numActivityRestarted % 3 == 0;
}
}
onRestart()
콜백 메서드는 액티비티가 백그라운드 상태로 전환되었다 다시 활성 상태로 전환될 때 호출됩니다. 따라서 이를 활용하면 앱 복귀 시점에 앱 오프닝 광고를 자연스럽게 보여줄 수 있습니다.
실행 및 테스트
이것으로 앱 구현이 모두 끝났습니다. 최초 실행시에는 광고가 로드되지 않은 상태이기에 광고가 표시되지 않지만, 이후에 앱을 다시 실행하면 앱 실행 하면에서 광고가 표시되는 것을 확인할 수 있습니다.
사용중이던 앱으로 다시 복귀하는 경우에도 앱 오프닝 광고가 잘 표시되는 것을 확인할 수 있습니다.
추가 리소스
앞서 살펴본 예제에서 사용한 AppOpenAdManager
클래스는 예제 수준에서 사용하기에는 큰 문제가 없지만, 확장성이 그리 좋지 않습니다. 여러 설정을 조금 더 입맛에 맞게 조정하여 사용하고 싶으신 분들은 아래 버전의 AppOpenAdManager
클래스를 사용하세요.
package com.androidhuman.ads.appopenads;
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.LoadAdError;
import com.google.android.gms.ads.appopen.AppOpenAd;
import android.app.Activity;
import android.app.Application;
import android.os.Bundle;
import android.util.Log;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import androidx.annotation.IntDef;
import androidx.annotation.IntRange;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
public class AppOpenAdManager extends AppOpenAd.AppOpenAdLoadCallback
implements Application.ActivityLifecycleCallbacks {
@Retention(RetentionPolicy.SOURCE)
@IntDef({AppOpenAd.APP_OPEN_AD_ORIENTATION_PORTRAIT,
AppOpenAd.APP_OPEN_AD_ORIENTATION_LANDSCAPE})
public @interface AdOrientation {
}
@Retention(RetentionPolicy.SOURCE)
@IntRange(from = 0L, to = MAX_AD_EXPIRY_DURATION)
public @interface AdExpiryDuration {
}
public static class Builder {
private final Application application;
private final String adUnitId;
@AdOrientation
private int orientation = AppOpenAd.APP_OPEN_AD_ORIENTATION_PORTRAIT;
@AdExpiryDuration
private long adExpiryDuration = MAX_AD_EXPIRY_DURATION;
private AdRequest adRequest = new AdRequest.Builder().build();
public Builder(@NonNull Application application, @NonNull String adUnitId) {
this.application = application;
this.adUnitId = adUnitId;
}
public Builder setOrientation(@AdOrientation int orientation) {
this.orientation = orientation;
return this;
}
public Builder setAdExpiryDuration(@AdExpiryDuration long duration) {
this.adExpiryDuration = duration;
return this;
}
public Builder setAdRequest(@NonNull AdRequest request) {
this.adRequest = request;
return this;
}
public AppOpenAdManager build() {
return new AppOpenAdManager(this);
}
}
public static final String TEST_AD_UNIT_ID = "ca-app-pub-3940256099942544/1033173712";
public static final long MAX_AD_EXPIRY_DURATION = 3600000 * 4;
private static final String TAG = "AppOpenManager";
private final Application application;
private final String adUnitId;
private final int orientation;
private final long adExpiryDuration;
private final AdRequest adRequest;
private Activity mostCurrentActivity;
private AppOpenAd ad;
private boolean isShowingAd = false;
private long lastAdFetchTime = 0L;
private AppOpenAdManager(Builder builder) {
this.application = builder.application;
this.adUnitId = builder.adUnitId;
this.orientation = builder.orientation;
this.adExpiryDuration = builder.adExpiryDuration;
this.adRequest = builder.adRequest;
// Used to keep track of most recent activity.
this.application.registerActivityLifecycleCallbacks(this);
}
public void showAdIfAvailable() {
showAdIfAvailable(null);
}
public void showAdIfAvailable(@Nullable final FullScreenContentCallback listener) {
if (this.isShowingAd) {
Log.e(TAG, "Can't show the ad: Already showing the ad");
return;
}
if (!isAdAvailable()) {
Log.d(TAG, "Can't show the ad: Ad not available");
fetchAd();
return;
}
FullScreenContentCallback callback = new FullScreenContentCallback() {
@Override
public void onAdFailedToShowFullScreenContent(AdError error) {
if (listener != null) {
listener.onAdFailedToShowFullScreenContent(error);
}
}
@Override
public void onAdShowedFullScreenContent() {
if (listener != null) {
listener.onAdShowedFullScreenContent();
}
AppOpenAdManager.this.isShowingAd = true;
}
@Override
public void onAdDismissedFullScreenContent() {
if (listener != null) {
listener.onAdDismissedFullScreenContent();
}
isShowingAd = false;
AppOpenAdManager.this.ad = null;
fetchAd();
}
};
ad.show(mostCurrentActivity, callback);
}
private void fetchAd() {
if (isAdAvailable()) {
return;
}
AppOpenAd.load(application, adUnitId, adRequest, orientation, this);
}
private boolean isAdAvailable() {
return this.ad != null && !isAdExpired();
}
private boolean isAdExpired() {
return System.currentTimeMillis() - lastAdFetchTime > adExpiryDuration;
}
// AppOpenAd.AppOpenAdLoadCallback implementations
@Override
public void onAppOpenAdLoaded(AppOpenAd ad) {
Log.d(TAG, "Ad loaded");
this.lastAdFetchTime = System.currentTimeMillis();
this.ad = ad;
}
@Override
public void onAppOpenAdFailedToLoad(LoadAdError error) {
Log.d(TAG, "Failed to load an ad: " + error.getMessage());
}
// Application.ActivityLifecycleCallbacks implementations
@Override
public void onActivityCreated(@NonNull Activity activity, @Nullable Bundle savedInstanceState) {
// Do nothing
}
@Override
public void onActivityStarted(@NonNull Activity activity) {
// Do nothing
}
@Override
public void onActivityResumed(@NonNull Activity activity) {
this.mostCurrentActivity = activity;
}
@Override
public void onActivityPaused(@NonNull Activity activity) {
// Do nothing
}
@Override
public void onActivityStopped(@NonNull Activity activity) {
// Do nothing
}
@Override
public void onActivitySaveInstanceState(@NonNull Activity activity, @NonNull Bundle outState) {
// Do nothing
}
@Override
public void onActivityDestroyed(@NonNull Activity activity) {
// Do nothing
}
}
이 글에서 작성한 예제 프로젝트 소스 코드는 Github 내 kunny/blog_samples 저장소에서 확인할 수 있습니다.