만족
[Android] admob 전면 광고의 적절한 로딩 시점과 표시 시점 본문
[Android] admob 전면 광고의 적절한 로딩 시점과 표시 시점
FrontEnd/Android Satisfaction 2022. 12. 12. 02:13이번에 전면 광고의 로딩 시점과 표시 시점을 변경하여,
그렇게 변경한 이유와 장점에 대해 소개한다.
기존
기존에는 스플래시 화면이 초기화될 때(onCreate)에서 로딩을 시작하고,
3초를 기다리거나 그 전에 광고가 로딩된 경우 표시했다.
그러나 admob의 응답 속도는 그다지 빠르지 않으며,
네트워크가 느린 환경에 있는 유저도 꽤나 많았기 때문에 노출률이 그다지 높지 않았다.
https://satisfactoryplace.tistory.com/133
광고 가이드도 의외로 빡세기 때문에 로딩이 끝났다고 냅다 띄울수도 없어서 고민이 많았다.
그래서 전면 광고와 네이티브 광고(이 경우 로딩이 좀 더 빠르다)를 동시에 로딩하고
표시 시점에 전면 광고가 없을 경우에 네이티브 광고라도 다이얼로그에 띄웠다.
하지만 이 행위는 전면 광고의 로딩 성공 가능성을 떨어뜨리게 되어
전면 광고의 노출률을 오히려 더 떨어뜨렸다.
플로우를 요약하자면 이렇다.
1. 스플래시 화면 표시
2. 전면/네이티브 광고 로딩 시작 + 초기 필수 데이터 로딩 시작
3. 초기 필수 데이터 로딩이 완료된 후 최대 3초간 전면 광고 로딩 대기
4. 전면 광고가 로딩되지 않은 경우 네이티브 광고 표시
5. 네이티브 광고도 표시되지 않은 경우 그냥 홈 화면으로 이동
무조건 광고는 스플래시에서 표시까지 끝내야 한다는 강박에 사로잡혀
어떻게 하면 광고가 로딩되는 동안 불쾌감을 최소화할 수 있을까? 에만 집중했었다.
무조건 스플래시에서 로딩, 표시까지 끝내야 할까?
생각해보면 아니다.
간단한 답이지만 몇년동안 이 생각에 갇혀 있었다.
Admob에서는 로딩 화면(스플래시) 또는 홈 화면에서 사용자가 인터렉션을 시작한 후 전면 광고를 표시하는 것을 강제한다.
그렇다면 로딩 시작을 스플래시에서 하고,
홈 화면에서 유저가 다른 창으로 이동할 때나 다른 창에서 돌아왔을 때 표시하면 어떨까?
좋은 방법이라고 생각한다.
기존에는 광고 때문에 최대 3초를 스플래시 화면에서 허비해야 했지만,
이제는 필수 데이터 로딩만 완료되면 홈으로 바로 진입할 수 있기 때문이다.
내 앱의 홈 화면은 네이게이션 역할을 하고 있다.
따라서 스플래시에서 미리 로딩을 걸어 놨다가,
다른 액티비티가 열릴 때 로딩이 완료된 경우 광고를 표시한 다음 그 액티비티를 열게 변경했다.
어떤가?
수정 후에서는 앱의 홈에 진입하기까지 훨씬 적은 시간이 요구되어 훨씬 쾌적해졌다.
로딩/표시 시점 미루기
애드몹 문서의 예제 코드에서는 액티비티 초기화 시점에 로딩을 시작하고, 로딩이 완료되면 표시한다.
그러나 우리가 하고 싶은 것은 로딩은 스플래시에서,
로딩이 완료되었다면 홈 화면에서 다른 화면으로 이동할 때(콜백을 붙일 수 있다면 굳이 이동이 아니더라도 상관없다) 표시하는 것이다.
따라서, 로딩과 표시 로직을 분리해 별도의 클래스를 만든다.
package kr.co.dothome.whenever.cyphersapp.ui.util;
import android.content.Context;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.google.android.gms.ads.AdListener;
import com.google.android.gms.ads.AdRequest;
import com.google.android.gms.ads.InterstitialAd;
public class AdmobUtil {
@NonNull
private InterstitialAd mInterstitialAd;
private boolean showedFullsizeAd = false;
private AdmobUtil(Context context) {
load(context);
}
private static AdmobUtil instance;
public static AdmobUtil getInstance(Context context) {
if (instance == null) {
instance = new AdmobUtil(context);
}
return instance;
}
/**
* load method is automatically called whe creating instance
* if re-call load(), reload is running
*
* @param context
*/
public void load(Context context) {
mInterstitialAd = new InterstitialAd(context);
mInterstitialAd.setAdUnitId("AD_UNIT_ID");
mInterstitialAd.loadAd(new AdRequest.Builder().build());
mInterstitialAd.setAdListener(new AdListener() {
@Override
public void onAdFailedToLoad(int i) {
super.onAdFailedToLoad(i);
//retry
load(context);
}
});
showedFullsizeAd = false;
}
// 광고가 로딩되었는가(표시 가능한가)?
public boolean isLoadedFullsizeAd() {
return mInterstitialAd.isLoaded();
}
// 로딩된 광고가 노출이 된 적이 있는가?
public boolean isShowedFullsizeAd() {
return showedFullsizeAd;
}
/**
* require checking activity is top(foreground) state
*
* @param onClose onClose callback
*/
public void showFullsizeAd(@Nullable Runnable onClose) {
if (!isLoadedFullsizeAd()) {
Log.d("AdmobUtil", "fullsize ad is not loaded but show() is called");
return;
}
if(showedFullsizeAd){
//already showed
if (onClose != null) {
onClose.run();
}
return;
}
mInterstitialAd.setAdListener(new AdListener() {
@Override
public void onAdOpened() {
super.onAdOpened();
}
@Override
public void onAdClosed() {
super.onAdClosed();
if (onClose != null) {
onClose.run();
}
}
});
showedFullsizeAd = true;
mInterstitialAd.show();
}
}
AdmobUtil은 Singleton 패턴으로 작성되어,
AdmobUtil.getInstance(context)로 어디서든 활용할 수 있다.
이제 스플래시 액티비티에서 로딩을 시작해 준다.
public class SplashActivity{
//...
@Override
protected void onCreate(Bundle savedInstance){
//...
// AdmobUtil 초기화
AdmobUtil.getInstance(this);
}
//...
}
AdmobUtil의 생성자에서 load(context)를 호출하게 해 두었기 때문에 여기에서는 그냥 getInstance만 해줘도 된다.
스플래시에서 홈 화면(이하 메인 액티비티)으로 이동하고 나면,
이제 위에서 설명한 '적절한 시점'에 광고를 표시할 것이다.
public class MainActivity{
//...
private void checkAdShowed(Runnable callback) {
AdmobUtil admobUtil = AdmobUtil.getInstance(this);
if (!admobUtil.isShowedFullsizeAd() && admobUtil.isLoadedFullsizeAd()) {
// loaded but not showed
// start show
Toast.makeText(this, "앱을 열고 나서 한 번 전면 광고가 표시됩니다\n닫기(Close) 버튼을 눌러 닫을 수 있습니다", Toast.LENGTH_LONG).show();
admobUtil.showFullsizeAd(callback);
} else {
// not loaded or already showed
if (callback != null)
callback.run();
}
}
//...
}
checkAdShowed는 광고가 로딩되었는지와 이미 표시된적이 있는지를 체크하고,
조건에 맞을 경우 표시하는 코드다.
이 메서드를 새로운 액티비티를 여는 메서드 전에 먼저 실행할 것이다.
새로운 액티비티를 연다?
바로 startActivity, startActivityForResult다.
이놈들을 override해서,
광고를 표시할 수 있는 상태면 표시한 다음 super메서드가 실행되게 한다.
public class MainActivity{
//...
private void checkAdShowed(Runnable callback) {
AdmobUtil admobUtil = AdmobUtil.getInstance(this);
if (!admobUtil.isShowedFullsizeAd() && admobUtil.isLoadedFullsizeAd()) {
// loaded but not showed
// start show
Toast.makeText(this, "앱을 열고 나서 한 번 전면 광고가 표시됩니다\n닫기(Close) 버튼을 눌러 닫을 수 있습니다", Toast.LENGTH_LONG).show();
admobUtil.showFullsizeAd(callback);
} else {
// not loaded or already showed
if (callback != null)
callback.run();
}
}
@Override
public void startActivity(Intent intent) {
checkAdShowed(() -> {
super.startActivity(intent);
});
}
@Override
public void startActivityForResult(Intent intent, int requestCode) {
checkAdShowed(() -> {
super.startActivityForResult(intent, requestCode);
});
}
//...
}
이제 다른 액티비티를 열기 전에 전면 광고 표시여부를 판단하여
광고를 표시한 다음 액티비티를 열게 할 수 있다.
그런데 만약 사용자가 홈 화면에 진입하자마자 다른 액티비티로 진입하고 (아직 광고는 로드되지 않은 상태)
용무를 끝낸 후 홈 화면으로 돌아온 다음 뒤로가기를 눌러 앱을 종료하는 상황을 상상해 보자.
유저는 홈 화면에서 연 액티비티에서 많은 시간을 보냈지만,
홈으로 돌아온 다음에도 광고는 표시되지 않았다.
다른 액티비티를 열었다가 닫는 콜백 메서드로 onActivityResult가 있지만,
이것은 startActivityForResult로 액티비티를 열었을 때만 실행된다.
따라서 홈 화면에서 onPause(다른 액티비티가 띄워질 때 이 라이프사이클에 진입한다) 상태로 진입한 적이 있다면,
onResume에서 다시 한번 checkAdShowed를 호출해 준다.
public class MainActivity{
//...
private boolean isPauseHistory= false;
private void checkAdShowed(Runnable callback) {
AdmobUtil admobUtil = AdmobUtil.getInstance(this);
if (!admobUtil.isShowedFullsizeAd() && admobUtil.isLoadedFullsizeAd()) {
// loaded but not showed
// start show
Toast.makeText(this, "앱을 열고 나서 한 번 전면 광고가 표시됩니다\n닫기(Close) 버튼을 눌러 닫을 수 있습니다", Toast.LENGTH_LONG).show();
admobUtil.showFullsizeAd(callback);
} else {
// not loaded or already showed
if (callback != null)
callback.run();
}
}
@Override
public void startActivity(Intent intent) {
checkAdShowed(() -> {
super.startActivity(intent);
});
}
@Override
public void startActivityForResult(Intent intent, int requestCode) {
checkAdShowed(() -> {
super.startActivityForResult(intent, requestCode);
});
}
@Override
protected void onResume() {
super.onResume();
if (isPausedHistory) {
checkAdShowed(null);
}
}
@Override
protected void onPause() {
super.onPause();
isPausedHistory = true;
}
//...
}
isPauseHistory로 체크하지 않으면,
전면 광고가 빠르게 로딩되었을 때, 또는 스플래시에서 초기 데이터 셋팅이 오래 걸렸을 때
홈 화면의 onResume에서 갑자기 광고가 표시될 수도 있다.
이는 정책 위반이므로 onPause()에 걸린 적이 있는지 확인한 다음 표시한다.
'FrontEnd > Android' 카테고리의 다른 글
[Android] 전면 광고가 로딩되었음에도 표시되지 않는 현상 (0) | 2023.02.21 |
---|---|
[Android] Admob 정책 위반 수정: Google 게재 광고를 완전히 또는 부분적으로 가리는 콘텐츠 (0) | 2023.02.13 |
[Android] 업데이트 제출을 위한 targetSDK 31이상(33) 업데이트와 관련 오류 수정 (0) | 2022.12.12 |
[Android] github action을 이용한 플레이스토어 앱 자동 배포하기 (0) | 2022.11.07 |
[Android] Material Chip 컴포넌트 사용하기 (0) | 2022.04.11 |