【Android】全面広告を表示する

無料アプリの収益化で利用するAdMob広告において、全面に表示される Interstitial型広告についての実装です。

この広告はバナー型より収益が見込めますが、あまり頻繁に表示されるとユーザーにとってあまり印象がよくありません。そのため起動時、3回に1回の頻度等に制限するのがベターです。

また、バナー型に比べて広告の読み込み処理に時間がかかるのと、画面全体に表示されるため、いきなり出てきた場合ユーザーの誤クリックを招いてしまいます。そのため広告のローディング中はプログレスダイアログを出して操作不可にしておく処理を入れておくと良いです。プログレスダイアログに関しては以下の記事にまとめています。

WebViewのロード完了までプログレスダイアログを表示する

事前準備として、広告タイプがインタースティシャル型の、adUnitIdを発行します。※adUnitIdの発行については以下をご確認ください。

Androidアプリでバナー型広告を表示する

実装

ライブラリの追加

app/build.gradle

まずはバナー型と同様、以下のライブラリをdependenciesに追加します。

compile 'com.google.android.gms:play-services:+'

権限の追加

AndroidManifest.xml

こちらもバナー型と同様です。

<uses-permission android:name="android.permission.INTERNET" />

広告IDの設定

values/string.xml

インタースティシャル型で発行したadUnitIdを定義します。

<string name="interstitial_ad_unit_id">ca-app-pub-3940256099942544/1033173712</string>

全面広告のインスタンス取得

これは広告のインスタンス取得をメソッドにしたものです。メインスレッドで呼び出します。

/**
 * 全面広告のインスタンスを取得
 * @return InterstitialAd
 */
private InterstitialAd newInterstitialAd() {
    InterstitialAd interstitialAd = new InterstitialAd(this);

    interstitialAd.setAdUnitId(getString(R.string.interstitial_ad_unit_id));
    interstitialAd.setAdListener(new AdListener() {
        @Override
        public void onAdLoaded() {
            Log.d(getClass().getName(), "onAdLoaded()");
        }

        @Override
        public void onAdFailedToLoad(int errorCode) {
            Log.d(getClass().getName(), "onAdFailedToLoad(" + errorCode + ")");
        }

        @Override
        public void onAdClosed() {
            Log.d(getClass().getName(), "onAdClosed()");
            goToNextLevel();
        }
    });

    return interstitialAd;
}

全面広告のローディング開始

メンバ変数(interstitialAd)へ取得した広告インスタンスに対して広告の読み込みを開始します。

/**
 * 全面広告の読み込み
 */
private void loadInterstitial() {
    AdRequest adRequest = new AdRequest.Builder().setRequestAgent("android_studio:ad_template").build();
    interstitialAd.loadAd(adRequest);
}

プログレスダイアログの生成と表示

// ローディング中はプログレスダイアログを表示して操作不可にする
final ProgressDialog progressDialog = new ProgressDialog(this);
progressDialog.setTitle(getString(R.string.app_name));
progressDialog.setMessage("Loading...");
progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
progressDialog.setCancelable(false);
progressDialog.show();

スレッド開始

Timer処理で0.5秒間隔で繰り返し処理を行い、広告のローディングが完了しているかをチェックします。ローディング完了、もしくは読み込みに失敗することもあるので規定回数に到達したら処理を終了してます。

スレッド内ではhandler内で処理することで、処理完了の際にメインスレッドのUIを更新します。

// 読み込み完了時にViewを更新するため、handlerを使用する
final Handler handler = new Handler();

new Timer().scheduleAtFixedRate(new TimerTask() {
    @Override
    public void run() {
        handler.post(new Runnable() {
            @Override
            public void run() {
                // 読み込みが完了(isLoaded)したか、0.5秒×30回読み込みに失敗したら終了と判断
                if((interstitialAd != null && interstitialAd.isLoaded()) || adLoadCount >= AD_LOAD_TIMEOUT) {
                    // タイマーを終了
                    cancel();

                    // ダイアログを終了
                    progressDialog.dismiss();

                    if(interstitialAd != null) { // 読み込みOK
                        // 読み込みOKのときはshowInterstitialを呼び出して全面広告を表示します
                        // アプリの起動毎に表示するとユーザーに良い印象を与えないのである程度制限します
                        // count % 3 == 1 の条件をつけることで、初回起動時は表示せず、2回目、5回目、8回目・・・、といった具合で表示しています
                        int count = preferences.getInt("count", 0);
                        textInterstitialTest.setText("load completed!\ncount:" + count);
                        if (count % 3 == 1) {
                            showInterstitial();
                        }

                        // アプリの起動回数をSharedPreferencesに記録する
                        SharedPreferences.Editor editor = preferences.edit();
                        count++;
                        editor.putInt("count", count);
                        editor.commit();
                    } else{ // 読み込み失敗
                        textInterstitialTest.setText("load failed!");
                    }
                } else{
                    // ロード中
                    adLoadCount++;
                    Log.d(getClass().getName(), "ad_load:" + adLoadCount);
                    if(adLoadCount >= AD_LOAD_TIMEOUT){
                        interstitialAd = null;
                    }
                }
            }
        });
    }
}, 0, 500);

ソースコード全体

MainActivity.java [クリックで表示]

package com.example.interstitialtest;

import android.app.ProgressDialog;
import android.content.SharedPreferences;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
import java.util.Timer;
import java.util.TimerTask;
import com.google.android.gms.ads.AdListener;
import com.google.android.gms.ads.AdRequest;
import com.google.android.gms.ads.InterstitialAd;

public class MainActivity extends AppCompatActivity {

    // 全面広告のインスタンス
    private InterstitialAd interstitialAd;

    // ロードチェックの上限
    // 読み込みの完了チェックの回数がこの数を超えた場合、失敗と判断する
    public static int AD_LOAD_TIMEOUT = 30;

    // ロードチェックの回数
    private int adLoadCount = 0;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 全面広告のインスタンスを生成しロードを開始する
        interstitialAd = newInterstitialAd();
        loadInterstitial();

        // レイアウトに配置したView(広告のロード完了時にテキストを設定する)
        final TextView textInterstitialTest = findViewById(R.id.textInterstitialTest);

        // ローディング中はプログレスダイアログを表示して操作不可にする
        final ProgressDialog progressDialog = new ProgressDialog(this);
        progressDialog.setTitle(getString(R.string.app_name));
        progressDialog.setMessage("Loading...");
        progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
        progressDialog.setCancelable(false);
        progressDialog.show();

        final SharedPreferences preferences = getSharedPreferences("preference", MODE_PRIVATE);
        final Handler handler = new Handler();

        new Timer().scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        // 読み込みが完了(isLoaded)したか、0.5秒×30回読み込みに失敗したら終了と判断
                        if((interstitialAd != null && interstitialAd.isLoaded()) || adLoadCount >= AD_LOAD_TIMEOUT) {
                            // タイマーを終了
                            cancel();

                            // ダイアログを終了
                            progressDialog.dismiss();

                            if(interstitialAd != null) { // 読み込みOK
                                // 読み込みOKのときはshowInterstitialを呼び出して全面広告を表示します
                                // アプリの起動毎に表示するとユーザーに良い印象を与えないのである程度制限します
                                // count % 3 == 1 の条件をつけることで、初回起動時は表示せず、2回目、5回目、8回目・・・、といった具合で表示しています
                                int count = preferences.getInt("count", 0);
                                textInterstitialTest.setText("load completed!\ncount:" + count);
                                if (count % 3 == 1) {
                                    showInterstitial();
                                }

                                // アプリの起動回数をSharedPreferencesに記録する
                                SharedPreferences.Editor editor = preferences.edit();
                                count++;
                                editor.putInt("count", count);
                                editor.commit();
                            } else{ // 読み込み失敗
                                textInterstitialTest.setText("load failed!");
                            }
                        } else{
                            // ロード中
                            adLoadCount++;
                            Log.d(getClass().getName(), "ad_load:" + adLoadCount);
                            if(adLoadCount >= AD_LOAD_TIMEOUT){
                                interstitialAd = null;
                            }
                        }
                    }
                });
            }
        },0,500);
    }

    /**
     * 全面広告の表示
     */
    private void showInterstitial() {
        if(interstitialAd != null && interstitialAd.isLoaded()) {
            interstitialAd.show();
        } else{
            goToNextLevel();
        }
    }

    /**
     * 全面広告の読み込み
     */
    private void loadInterstitial() {
        AdRequest adRequest = new AdRequest.Builder().setRequestAgent("android_studio:ad_template").build();
        interstitialAd.loadAd(adRequest);
    }

    /**
     * 続けて表示する場合に新たにインスタンスを生成
     */
    private void goToNextLevel() {
        interstitialAd = newInterstitialAd();
        loadInterstitial();
    }

    /**
     * 全面広告のインスタンスを取得
     * @return InterstitialAd
     */
    private InterstitialAd newInterstitialAd() {
        InterstitialAd interstitialAd = new InterstitialAd(this);

        interstitialAd.setAdUnitId(getString(R.string.interstitial_ad_unit_id));
        interstitialAd.setAdListener(new AdListener() {
            @Override
            public void onAdLoaded() {
                Log.d(getClass().getName(), "onAdLoaded()");
            }

            @Override
            public void onAdFailedToLoad(int errorCode) {
                Log.d(getClass().getName(), "onAdFailedToLoad(" + errorCode + ")");
            }

            @Override
            public void onAdClosed() {
                Log.d(getClass().getName(), "onAdClosed()");
                goToNextLevel();
            }
        });

        return interstitialAd;
    }
}

実行結果

アプリケーションを起動すると広告のローディングとともにプログレスダイアログが表示されます。

また2回めの起動では左の画像のように広告が表示されます。

サンプルソースコード

今回作成したサンプルを以下にアップしておきました。

https://github.com/s-watanabe-apps/android-admobtest-interstitial

コメント

このブログの人気の投稿

docker-compose up で proxyconnect tcp: dial tcp: lookup proxy.example.com: no such host

docker-compose で起動したweb、MySQLに接続できない事象

【PHP】PHP_CodeSnifferを使う(コーディングルールのカスタマイズ)