- 更新日: 2019年06月14日
- 公開日: 2019年06月12日
【はじめてのAndroidアプリ開発】動画リワード広告を使ってみよう
Androidのアプリ開発をはじめようと考えている方、もしくははじめたばかりの方向けにお届けしている 【はじめてのAndroidアプリ開発】 シリーズ。 今回は 『動画リワード広告』の使い方をご紹介。
アプリ収益の最大化、動画リワード広告が手伝ってくれるかもしれませんよ。
★本稿はこんな方に役立ちます★
- Android アプリ開発初心者
- アプリの収益化を考えておられる方
- 動画リワード広告を検討されている方
- アプリの表示時間に応じたプログラム制御を考えておられる方
★開発環境★
・ Android Studio 3.4
・ Java
・ エミュレーター Android 9 (Pie)
・ 動画リワード広告(AdMob)
動画リワード広告
動画リワード広告とは
画像クリックで拡大
動画リワード広告(Rewarded Video Ads)は、現在右肩上がりの広告手法で、 ユーザーと広告主両方が Win-Win の関係を築けるナイスなビジネス戦略です。
具体的な流れとしては、例えばユーザーがゲーム内のアイテムを欲しいと思った時。 一般的にはアイテムを購入して取得となるところを、動画リワード広告の場合は動画広告を視聴することでタダでアイテムをゲットすることが可能。そしてアプリ運営側は広告料をゲット。
新しくアイテムをゲットしたユーザーはさらにゲームを利用し、再び新しいアイテムをゲットするために動画広告もしくはアイテム購入でアプリビジネスに寄与してくれると考えられます。
【動画リワード広告の市場規模】
img: Digital InFact
日本国内の動画リワード広告の市場規模は 300億円程度ですが、アメリカにおいては 1兆6000億円*程の市場規模を誇り、 さらに 2022年までに 2兆5000億円ほどの規模に膨れ上がるという予測結果も。
今後ますますスマートフォンの普及率が高まると共に、動画リワード広告の市場規模も高まると考えられますね。
動画リワード広告のメリット
高いCPM
広告手法 | CPM |
---|---|
バナー | $ 0.45 |
インタースティシャル | $ 9 |
動画リワード | $ 14 |
動画リワード広告は、一般的に収益率が高いと言われています。 上記のように広告毎の CPM を比較してみると、動画リワードが圧倒的に高いです。
CPM ・・・ 広告 1000回あたりの報酬額
アプリ内課金との相乗効果に期待
アプリ内でアイテムやポイントが欲しいと思った時、ユーザーによっては広告視聴より手早くアイテムを入手できる課金という選択肢を選ぶ方もいるでしょう。 Spotify などのアップグレード・ビジネスが成功していることを考えると、アプリ内課金と動画リワード広告のハイブリッド手法、うまくいきそうな気がしますよね。
比較的好かれやすい広告
バナー広告やインタースティシャル広告に比べて、動画で広告を表示しますので、広告がどんな展開になるのか気になるもの。 YouTube の広告やテレビコマーシャルを思い浮かべると、広告自体が楽しかったりしますよね。 そのためユーザーから批判を浴びにくい広告といえるでしょう。
動画リワード広告を採用しているアプリ
動画広告を視聴することで、ユーザーはポイントをゲットしたり、ゲームクリアのためのヒントを得たり、機能強化したりなど、よりゲームを楽しむ為のアイテムをゲット。 アプリ運営側としては、アプリ利用時間増加に伴って、広告収入増やアプリ内課金に期待できますね。
動画リワード広告を提供しているプロバイダー
アプリの広告というと AdMob が有名ですが、動画リワード広告については AdMob 以外にもいくつかの会社があります。参考までに情報を把握しておきましょう。
動画リワード広告を使ってみよう
アプリ起動から一定時間経過すると動画リワード広告を表示するアプリ
今回作成するアプリについてご紹介。
画像クリックで拡大
【アプリの内容】
- アプリ起動から一定時間が経過すると動画広告表示
- 動画広告視聴で次の広告表示までの時間がプラス
- 動画広告視聴しなかった場合は次の広告表示までの時間がマイナス
【本アプリ制作から得られること】
- タイマーの使い方
- アプリ表示・非表示にリンクするタイマーのON・OFF
- 動画リワード広告の表示方法
- 広告視聴の有無に合わせた報酬処理
【開発環境】
- Android Studio 4.4
- Java
- AdMob
今回は AdMob のテスト用 ID を用いて動画リワード広告を表示しますので、現段階では AdMob にアカウント登録する必要はありません。
動画リワード広告を採用したタイマーアプリを作る様子
これからご紹介する動画リワードの実装方法を実際にテストしている様子の動画です。40分強ありますので、早送りしながら参考にしてみて下さい。文字や画像ではイメージできないクラスやメソッド、インターフェースの実装などが参考になると思います。
タイマー機能を設定
まずは「一定時間経過」を管理するためのタイマー機能装備から。タイマー機能については、Androidで標準用意されているクラス CountDownTimer を使用。早速 Android Studio を起動してプロジェクトの作成に取り掛かりましょう。
Android Studio ツールバーから New → New Project... を選択。
Empty Activity を選択。
プロジェクト名を入力して、Finish。
Gradleが安定したら、まずはレイアウトファイルの編集から。最初に用意されている 「Hello World」 の <TextView に id を付与します。
android:id="@+id/textView"
編集後のactivity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/textView"
android:textSize="40sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
idをセットすることで、プログラム MainActivity からここのテキスト部分の表示を操れるように。今回はタイマーの時刻を表示しようと思っています。
タイマー機能のプログラムを、クラス CountDownTimer で紹介されているサンプルコードからコピペします。コピペする前にメソッド timer() を準備しておきましょう。
timer() は任意の値。 appTimer() 、 screenTimer() など分かりやすいメソッド名にしましょう。
編集後の MainActivity
package com.oshimamasara.timer;
import android.os.CountDownTimer;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
timer();
}
private void timer() {
new CountDownTimer(30000, 1000) {
public void onTick(long millisUntilFinished) {
mTextField.setText("seconds remaining: " + millisUntilFinished / 1000);
}
public void onFinish() {
mTextField.setText("done!");
}
}.start();
}
}
コードを貼り付けた際、上図のような青色ポップアップが表示されると思います。
【青色ポップアップ】
android.os.CountDownTimer? Alt+Enter
この時はポップアップに書かれている通り、 Altキーを押しながら Enterキーを押してみましょう。クラス CountDownTimer を使うにあたって必要なクラスが import に追記されるでしょう。
画像クリックで拡大
クラス CountDownTimer のサンプルコードを貼り付けたところ、 setText()メソッドのプロパティ部分でエラーが出ています。これは setText() でテキストを編集したいけど、対象の Textがない というエラー。 mTextField を textView に変更すればよさそうですね。
画像クリックで拡大
エラーの出ていた mTextField を textView に変えてみましたが、エラー状況は変わりません。これは MainActivity がレイアウトファイル内の textView を認知していないため。プロパティのセットを行っておきましょう。
画像クリックで拡大
上記矢印部分のコードを追加することで、 MainActivity がレイアウトファイル内の textView を認知。先ほどエラー表示されていた textView.setText() のエラーも消えました。
onFinish()メソッド内の mTextField も textView に変えて、プログラムを実行してみましょう。今回はエミュレータ環境でプログラムを実行します。
タイマー機能を装備した MainActivity
package com.oshimamasara.timer;
import android.os.CountDownTimer;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView)findViewById(R.id.textView);
timer();
}
private void timer() {
new CountDownTimer(30000, 1000) {
public void onTick(long millisUntilFinished) {
textView.setText("seconds remaining: " + millisUntilFinished / 1000);
}
public void onFinish() {
textView.setText("done!");
}
}.start();
}
}
無事にタイマーが起動しました。しかし、現在の状況ではアプリを使用していなくても、非表示でもタイマーは進み、勝手に done! になっています。
このアプリ未使用時はタイマーを止めたい、という動きを加えようと思うと「アプリのライフサイクル」を制御する必要が。
アプリ非表示の時はタイマーをストップ
画像クリックで拡大
アプリを使っている時、使っていない時のタイミングに合わせて、何かイベントをしようと思った時、上図右のような Activity Lifecycle を利用できます。
いつもは一番上にある onCreate() を実行していると思いますが、その他にも onStart() や onPause() などアプリの操作状況に合わせてプログラムを操作することが可能。まずは onStart() や onPause() を MainActivity に追加しましょう。
【各工程の説明】
各工程 | 内容 |
---|---|
onCreate() | アクティビティを起動する時に呼び出される |
onStart() | アクティビティが見える状態になる前に呼び出される |
onResume() | アクティビティがユーザーからの操作を受付OKになった時 |
onPause() | アクティビティがユーザーからの操作を受付OFFになった時 |
onStop() | アクティビティが見えない状態になる前に呼び出される |
onRestart() | Stop後、再びアプリを起動した時 |
onDestory() | アクティビティ終了直前に呼び出される |
画像クリックで拡大
試しに onStart() を上図のように追加してみました。
【追加コード】
@Override
protected void onStart(){
super.onStart();
Toast.makeText(this, "スタート!", Toast.LENGTH_SHORT).show();
}
書き方は onCreate() と一緒で Override と super. を使ってメソッドを適切に制御。今回は、 onStart() が働いているか確認するために Toast 機能を装備してみました。プログラムを実行すると上図右のようにアプリ起動時、画面下に「スタート!」という文字が表示され、 onStart() が機能していることが確認できます。
onStart()以外のライフサイクル・イベントも追加しましょう。
画像クリックで拡大
編集後の MainActivity
package com.oshimamasara.timer;
import android.os.CountDownTimer;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.i(TAG,"★onCreate");
textView = (TextView)findViewById(R.id.textView);
timer();
}
private void timer() {
new CountDownTimer(30000, 1000) {
public void onTick(long millisUntilFinished) {
textView.setText("seconds remaining: " + millisUntilFinished / 1000);
}
public void onFinish() {
textView.setText("done!");
}
}.start();
}
@Override
protected void onStart(){
super.onStart();
Toast.makeText(this, "スタート!", Toast.LENGTH_SHORT).show();
Log.i(TAG,"★onStart");
}
@Override
protected void onResume(){
super.onResume();
Log.i(TAG,"★onResume");
}
@Override
protected void onPause(){
super.onPause();;
Log.i(TAG,"★onPause");
}
@Override
protected void onStop(){
super.onStop();
Log.i(TAG,"★onStop");
}
@Override
protected void onRestart(){
super.onRestart();
Log.i(TAG,"★onRestart");
}
@Override
protected void onDestroy(){
super.onDestroy();
Log.i(TAG,"★onDestroy");
}
}
各工程の動きを把握できるように、Logcat 出力も追記しました。この状態でアプリを起動しても、アプリ非表示でタイマーは止まりません。 onPause() 内にタイマーを止めるプログラムを追加してあげる必要があります。
画像クリックで拡大
今回は CountDownTimer() を操作できるように mCountDownTimer というプロパティをセット。こうすることで CountDownTimer() を止めたり、スタートしたりできるようになります。
今回は一時停止したいので cancel() を選択。
@Override
protected void onStop(){
super.onStop();
Log.i(TAG,"★onStop");
mCountDownTimer.cancel();
}
これでアプリ非表示時にタイマーを止めることができます。
画像クリックで拡大
実際にテストしてみると、確かにアプリ非表示時にはタイマー止まりますが、アプリ再開に合わせてタイマーが再開されません。onRestart() にタイマー再開のプログラムが必要ですね。
画像クリックで拡大
タイマーを再開しようと思うと CountDownTimer() を使っている timer() メソッドを呼びだせば良さそうですが、 どの時間から再開すればいいか、という時間の操作が必要となってきます。タイマーの経過時間は millisUntilFinished で扱っていますので、 millisUntilFinished の値を取得できれば途中からタイマーを再開できそう。
経過時間 millisUntilFinished を操作する前に、まずどの時間からタイマーを進めればいいか、ということをプログラムに指示する必要があります。この「どの時間から」というのは timer()メソッド内に引数を設定すればOK。
どの時間 = timer() 内の引数の時間 |
---|
まずはメソッド定義の中に引数をセットします。
private void timer(long time){
次に CountDownTimer() の中に先ほどの引数を割り当て。
mCountDownTimer = new CountDownTimer(time*1000, 1000) {
後はプログラムの中で使用している timer() メソッド内に引数を割り当てれば、 セットした引数の時間からタイマーが進みます。 今回はアプリを再開した際に、途中から時刻を刻みたいので
timer(millisUntilFinished);
とできれば良よさそうですが、 millisUntilFinished は定義されていませんので timer(millisUntilFinished) とするとエラーが出てしまいます。 上図のように millisUntilFinished を定義し、timeRemaining(残り時間) という変数を作成、そして millisUntilFinished の値を適切に操作できるようにプログラムしてみました。
以上の結果 timer(millisUntilFinished); で処理できなかったところを timer(timeRemaining); とすることで、残り時間からタイマーを起動することができるようになりました。
後はこの timer(timeRemaining); を onRestart() にセットすれば、アプリ再開時にタイマーを自動で起動できるようになるでしょう。
編集後の MainActivity
// ライフサイクル ログチェック
// タイマー停まる
package com.oshimamasara.timer;
import android.os.CountDownTimer;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
TextView textView;
private CountDownTimer mCountDownTimer;
private static long SET_TIME=10;
private long timeRemaining;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.i(TAG,"★onCreate");
textView = (TextView)findViewById(R.id.textView);
timer(SET_TIME);
}
private void timer(long time) {
mCountDownTimer = new CountDownTimer(time*1000, 1000) {
public void onTick(long millisUntilFinished) {
Log.i(TAG,"★millisUntilFinished "+millisUntilFinished);
timeRemaining=millisUntilFinished/1000;
textView.setText("seconds remaining: " + timeRemaining);
}
public void onFinish() {
textView.setText("done!");
Log.i(TAG,"終了");
}
}.start();
}
@Override
protected void onStart(){
super.onStart();
Log.i(TAG,"★onStart");
Toast.makeText(this, "スタート!", Toast.LENGTH_SHORT).show();
}
@Override
protected void onResume(){
super.onResume();
Log.i(TAG,"★onResume");
}
@Override
protected void onPause(){
super.onPause();;
Log.i(TAG,"★onPause");
}
@Override
protected void onStop(){
super.onStop();
Log.i(TAG,"★onStop");
mCountDownTimer.cancel();
}
@Override
protected void onRestart(){
super.onRestart();
Log.i(TAG,"★onRestart");
timer(timeRemaining);
}
@Override
protected void onDestroy(){
super.onDestroy();
Log.i(TAG,"★onDestroy");
}
}
アプリへのタイマーセットが完了できたら、後はタイマー終了時の done! を 動画リワード広告開始 に変更すれば、アプリ起動時間に応じて動画リワード広告を表示できそう。
次は動画リワード広告を再生できるように設定を進めていきましょう。
動画リワード広告を設定
アプリに AdMob の動画リワード広告を設定しようと思うと、
- AdMobのSDKをセット(build.gradle、 マニフェスト)
- 専用インターフェースのセット
- 動画リワード広告開始のプログラム
などいくつかの設定が必要となってきます。しかし、とりあえずどんなものか動画リワード広告を動かしたいと思う方も多いはず。
そんな時は GitHub に公開されている Google の動画リワード広告のサンプルが便利。プログラムをダウンロードして、 Android Studio にプロジェクトを読み込むだけで簡単に動画リワード広告をテストできます。
サンプルのアプリでは一定時間経過すると、広告を見てポイントを増やすかどうかの選択ボタンが表示。広告を見るボタンを選択すると動画リワード広告がスタート。そして広告を全て見終わるとポイントが加算。広告を途中で消した場合はポイントが加算されない、という動画リワード広告を考える上で非常に参考となるプログラムとなっています。
今回作成しているアプリのケースでは、広告視聴によって次の動画リワード広告が再生されるまでの時間を延期したいと思います。
アプリへの動画リワード広告設定
動画リワード広告を使用しようと思うと、 まずはアプリに AdMob の設定を行う必要が。AdMob の設定手順は、 Google AdMob の公式ドキュメントが参考となるでしょう。
画像クリックで拡大
最初に AdMob を利用するために必要な SDK の設定と AndroidManifest.xml の設定を行います。今回はとりあえず広告を表示できるテスト用の ID を使用。本番用の ID は、AdMob の管理ページから ID 取得を申請する必要があります。本番用の ID は、事前にアプリを公開しておく必要がありますので、今回はテスト版のみの使用とさせていただきました。
マニュアルにある通り、まずは build.gradle(アプリレベル) に下記コードを追加、そして SYNC NOW。
implementation 'com.google.android.gms:play-services-ads:17.2.1'
編集後の build.gradle(アプリレベル)
apply plugin: 'com.android.application'
android {
compileSdkVersion 28
defaultConfig {
applicationId "com.oshimamasara.myadrewardapp"
minSdkVersion 15
targetSdkVersion 28
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
implementation 'com.google.android.gms:play-services-ads:17.2.1'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test🏃1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}
次は AndroidManifest.xml に AdMob 利用のコードを記述。
<!-- Sample AdMob App ID: ca-app-pub-3940256099942544~3347511713 -->
<meta-data
android:name="com.google.android.gms.ads.APPLICATION_ID"
android:value34="ca-app-pub-3940256099942544~3347511713"/>
編集後の AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.oshimamasara.myadrewardapp">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!-- Sample AdMob App ID: ca-app-pub-3940256099942544~3347511713 -->
<meta-data
android:name="com.google.android.gms.ads.APPLICATION_ID"
android:value34="ca-app-pub-3940256099942544~3347511713"/>
</application>
</manifest>
AdMob の設定が完了したら、次は動画リワード広告の設定。現在動画リワード広告のプログラム(API)は、2種類提供されています。新しいバージョンの方がユーザーにマッチした広告を表示できる様子ですが、情報量が少ないので今回は従来型の Implement Rewarded Ads を選択。
画像クリックで拡大
動画リワード広告の設定ページに移動すると、いろいろプログラムが紹介されているのですが、ポイントは インターフェース RewardedVideoAdListener をまずは実装すること。
implements RewardedVideoAdListener
の設定を行ってから、 GitHub の動画リワード広告サンプルコードを利用すると、簡単に自分のアプリに動画リワード広告を設定することができます。インターフェース RewardedVideoAdListener の実装については以下の画像をご参考ください。
画像クリックで拡大
MainActivity 冒頭の public class MainActivity extends AppCompatActivity の後に
implements RewardedVideoAdListener
と追記すると、上図のようにエラーが表示されます。 Alt + Enter キーでエラーハンドリングしてみると、メソッドがないとのこと。「implement methods」 を選択してみましょう。
画像クリックで拡大
追加されるメソッド一覧が表示されますので、そのまま OK ボタンをクリック。
画像クリックで拡大
たくさんメソッドが追加されました。 でもメソッドがどのような働きをするのか分かりにくいので、下記の解説入りコードに書き換えてみました。
画像クリックで拡大
編集後のメソッド一覧コード
// TEXT https://developers.google.com/android/reference/com/google/android/gms/ads/reward/RewardedVideoAdListener
// 動画広告の準備完了時
@Override
public void onRewardedVideoAdLoaded() {
Toast.makeText(this, "onRewardedVideoAdLoaded", Toast.LENGTH_SHORT).show();
Log.i(TAG,"★onRewardedVideoAdLoaded:");
}
// 広告再生時
@Override
public void onRewardedVideoStarted() {
Toast.makeText(this, "onRewardedVideoStarted", Toast.LENGTH_SHORT).show();
Log.i(TAG,"★onRewardedVideoStarted:");
}
// 動画内の広告へ移動する時
@Override
public void onRewardedVideoAdOpened() {
Toast.makeText(this, "onRewardedVideoAdOpened", Toast.LENGTH_SHORT).show();
Log.i(TAG,"★onRewardedVideoAdOpened:");
}
// 動画広告→リンク→ブラウザ などアプリから離れる時
@Override
public void onRewardedVideoAdLeftApplication() {
Toast.makeText(this, "onRewardedVideoAdLeftApplication", Toast.LENGTH_SHORT).show();
Log.i(TAG,"★onRewardedVideoAdLeftApplication:");
}
// 動画視聴完了後の報酬
@Override
public void onRewarded(RewardItem rewardItem) {
Toast.makeText(this, "YES! I GOT", Toast.LENGTH_SHORT).show();
Log.i(TAG,"★onRewarded:");
}
// 広告視聴完了時
@Override
public void onRewardedVideoCompleted() {
Toast.makeText(this, "onRewardedVideoCompleted", Toast.LENGTH_SHORT).show();
Log.i(TAG,"★onRewardedVideoCompleted:");
}
// 動画広告閉じた時
@Override
public void onRewardedVideoAdClosed() {
Toast.makeText(this, "広告視聴ありがとうございました", Toast.LENGTH_SHORT).show();
Log.i(TAG,"★onRewardedVideoAdClosed:");
}
// 動画広告読み込み失敗時
@Override
public void onRewardedVideoAdFailedToLoad(int i) {
Toast.makeText(this, "onRewardedVideoAdFailedToLoad", Toast.LENGTH_SHORT).show();
Log.i(TAG,"★onRewardedVideoAdFailedToLoad:");
}
解説を入れてみると、どのメソッドがどのタイミングで働くのかイメージしやすいと思います。 ただこれらのプログラムは、動画広告が再生されてからの処理内容。まずは動画広告を再生するためのメソッドが必要となります。
画像クリックで拡大
動画リワード広告の再生プログラムについては、 GitHubのサンプルから拝借。まずはタイマー終了時に広告が再生されるように、
showRewardedVideo();
を上図のように追加。実際の showRewardedVideo(); 中身については、以下のようにプログラム。
画像クリックで拡大
private void showRewardedVideo() {
//textView.setVisibility(View.INVISIBLE);
if (rewardedVideoAd.isLoaded()) {
rewardedVideoAd.show();
}
}
あと動画リワード広告を再生しようと思うと、表示する前に事前に広告を読み込んでおく必要があります。その事前読み込み機能 loadRewardedVideoAd() については、以下のようにプログラム。
private void loadRewardedVideoAd() {
if (!rewardedVideoAd.isLoaded()) {
rewardedVideoAd.loadAd(AD_UNIT_ID, new AdRequest.Builder().build());
}
}
そして後は AdMob の ID や 広告読み込みのプログラムをセットすれば、タイマー完了後に動画広告を表示することができます(上図参照)。
編集後の MainActivity
// ライフサイクル ログチェック
// タイマー停まる
// 動画広告再生のみ
package com.oshimamasara.timer;
import android.os.CountDownTimer;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
import android.widget.Toast;
import com.google.android.gms.ads.AdRequest;
import com.google.android.gms.ads.MobileAds;
import com.google.android.gms.ads.reward.RewardItem;
import com.google.android.gms.ads.reward.RewardedVideoAd;
import com.google.android.gms.ads.reward.RewardedVideoAdListener;
public class MainActivity extends AppCompatActivity implements RewardedVideoAdListener {
private static final String TAG = "MainActivity";
TextView textView;
private CountDownTimer mCountDownTimer;
private static long SET_TIME=10;
private long timeRemaining;
private static final String AD_UNIT_ID = "ca-app-pub-3940256099942544/5224354917";
private static final String APP_ID = "ca-app-pub-3940256099942544~3347511713";
private RewardedVideoAd rewardedVideoAd;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.i(TAG,"★onCreate");
textView = (TextView)findViewById(R.id.textView);
MobileAds.initialize(this, APP_ID);
rewardedVideoAd = MobileAds.getRewardedVideoAdInstance(this);///
rewardedVideoAd.setRewardedVideoAdListener(this);
loadRewardedVideoAd();
timer(SET_TIME);
}
private void timer(long time) {
mCountDownTimer = new CountDownTimer(time*1000, 1000) {
public void onTick(long millisUntilFinished) {
Log.i(TAG,"★millisUntilFinished "+millisUntilFinished);
timeRemaining=millisUntilFinished/1000;
textView.setText("seconds remaining: " + timeRemaining);
}
public void onFinish() {
textView.setText("done!");
Log.i(TAG,"★終了");
// show ad
showRewardedVideo();
}
}.start();
}
private void loadRewardedVideoAd() {
if (!rewardedVideoAd.isLoaded()) {
rewardedVideoAd.loadAd(AD_UNIT_ID, new AdRequest.Builder().build());
}
}
private void showRewardedVideo() { ///
//textView.setVisibility(View.INVISIBLE);
if (rewardedVideoAd.isLoaded()) {
rewardedVideoAd.show();
}
}
@Override
protected void onStart(){
super.onStart();
Log.i(TAG,"★onStart");
Toast.makeText(this, "スタート!", Toast.LENGTH_SHORT).show();
}
@Override
protected void onResume(){
super.onResume();
Log.i(TAG,"★onResume");
}
@Override
protected void onPause(){
super.onPause();;
Log.i(TAG,"★onPause");
}
@Override
protected void onStop(){
super.onStop();
Log.i(TAG,"★onStop");
mCountDownTimer.cancel();
}
@Override
protected void onRestart(){
super.onRestart();
Log.i(TAG,"★onRestart");
timer(timeRemaining);
}
@Override
protected void onDestroy(){
super.onDestroy();
Log.i(TAG,"★onDestroy");
}
// TEXT https://developers.google.com/android/reference/com/google/android/gms/ads/reward/RewardedVideoAdListener
// 動画広告の準備完了時
@Override
public void onRewardedVideoAdLoaded() {
Toast.makeText(this, "onRewardedVideoAdLoaded", Toast.LENGTH_SHORT).show();
Log.i(TAG,"★onRewardedVideoAdLoaded:");
}
// 広告再生時
@Override
public void onRewardedVideoStarted() {
Toast.makeText(this, "onRewardedVideoStarted", Toast.LENGTH_SHORT).show();
Log.i(TAG,"★onRewardedVideoStarted:");
}
// 動画内の広告へ移動する時
@Override
public void onRewardedVideoAdOpened() {
Toast.makeText(this, "onRewardedVideoAdOpened", Toast.LENGTH_SHORT).show();
Log.i(TAG,"★onRewardedVideoAdOpened:");
}
// 動画広告→リンク→ブラウザ などアプリから離れる時
@Override
public void onRewardedVideoAdLeftApplication() {
Toast.makeText(this, "onRewardedVideoAdLeftApplication", Toast.LENGTH_SHORT).show();
Log.i(TAG,"★onRewardedVideoAdLeftApplication:");
}
// 動画視聴完了後の報酬
@Override
public void onRewarded(RewardItem rewardItem) {
Toast.makeText(this, "YES! I GOT", Toast.LENGTH_SHORT).show();
Log.i(TAG,"★onRewarded:");
}
// 広告視聴完了時
@Override
public void onRewardedVideoCompleted() {
Toast.makeText(this, "onRewardedVideoCompleted", Toast.LENGTH_SHORT).show();
Log.i(TAG,"★onRewardedVideoCompleted:");
}
// 動画広告閉じた時
@Override
public void onRewardedVideoAdClosed() {
Toast.makeText(this, "広告視聴ありがとうございました", Toast.LENGTH_SHORT).show();
Log.i(TAG,"★onRewardedVideoAdClosed:");
}
// 動画広告読み込み失敗時
@Override
public void onRewardedVideoAdFailedToLoad(int i) {
Toast.makeText(this, "onRewardedVideoAdFailedToLoad", Toast.LENGTH_SHORT).show();
Log.i(TAG,"★onRewardedVideoAdFailedToLoad:");
}
}
めでたく動画リワード広告をアプリ内で利用できるようになったわけですが、動画広告終了後、画面は done! のままで何も動きません。
今回の一定時間経過すると動画リワード広告を表示、というアプリ内容を考えると、広告終了後も再びタイマーが起動し、再度動画リワード広告を表示したいもの。これらの広告完了後の処理については onRewardedVideoAdClosed() にプログラムを追加してあげれば OK。
広告視聴後の報酬や動きを設定
画像クリックで拡大
広告視聴後、再びタイマーを稼働させる前に、ユーザーへの特典プログラムを用意しておきたいと思います。今回の場合は
「次の動画広告表示までの時間延長」
広告視聴におけるユーザー特典は、 onRewarded() 内に記述。今回の場合は時間を延長したいので
SET_TIME = SET_TIME + 5;
そして広告完了後の処理については、
loadRewardedVideoAd();
timer(SET_TIME);
編集後の MainActivity
// 動画広告 繰り返し視聴
// 広告視聴を途中で辞めた場合などの制約なし
package com.oshimamasara.myadrewardapp;
import android.os.CountDownTimer;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
import android.widget.Toast;
import com.google.android.gms.ads.AdRequest;
import com.google.android.gms.ads.MobileAds;
import com.google.android.gms.ads.reward.RewardItem;
import com.google.android.gms.ads.reward.RewardedVideoAd;
import com.google.android.gms.ads.reward.RewardedVideoAdListener;
public class MainActivity extends AppCompatActivity implements RewardedVideoAdListener {
private static final String TAG = "MainActivity";
TextView textView;
private CountDownTimer mCountDownTimer;
private static long SET_TIME = 10;
private long timeRemaining;
private static final String AD_UNIT_ID = "ca-app-pub-3940256099942544/5224354917";///
private static final String APP_ID = "ca-app-pub-3940256099942544~3347511713";
private RewardedVideoAd rewardedVideoAd;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.i(TAG,"★onCreate");
textView = (TextView)findViewById(R.id.textView);
MobileAds.initialize(this, APP_ID);
rewardedVideoAd = MobileAds.getRewardedVideoAdInstance(this);///
rewardedVideoAd.setRewardedVideoAdListener(this);
loadRewardedVideoAd();
timer(SET_TIME);
}
private void timer(long time) {
mCountDownTimer = new CountDownTimer(time*1000, 1000) {
public void onTick(long millisUntilFinished) {
timeRemaining = millisUntilFinished/1000;
textView.setText("seconds remaining: " + timeRemaining);
}
public void onFinish() {
textView.setText("done!");
Log.i(TAG,"★終了");
//広告スタート
showRewardedVideo();
}
}.start();
}
private void loadRewardedVideoAd() {
if (!rewardedVideoAd.isLoaded()) {
rewardedVideoAd.loadAd(AD_UNIT_ID, new AdRequest.Builder().build());
}
}
private void showRewardedVideo() { ///
//textView.setVisibility(View.INVISIBLE);
if (rewardedVideoAd.isLoaded()) {
rewardedVideoAd.show();
}
}
@Override
protected void onStop(){
super.onStop();
Log.i(TAG,"★onStop");
mCountDownTimer.cancel();
}
@Override
protected void onRestart(){
super.onRestart();
Log.i(TAG,"★onRestart");
timer(timeRemaining);
}
@Override
protected void onStart(){
super.onStart();
Toast.makeText(this, "スタート!", Toast.LENGTH_SHORT).show();
Log.i(TAG,"★onStart");
}
@Override
protected void onResume(){
super.onResume();
Log.i(TAG,"★onResume");
}
@Override
protected void onPause(){
super.onPause();;
Log.i(TAG,"★onPause");
}
@Override
protected void onDestroy(){
super.onDestroy();
Log.i(TAG,"★onDestroy");
}
// TEXT https://developers.google.com/android/reference/com/google/android/gms/ads/reward/RewardedVideoAdListener
// 動画広告の準備完了時
@Override
public void onRewardedVideoAdLoaded() {
Toast.makeText(this, "onRewardedVideoAdLoaded", Toast.LENGTH_SHORT).show();
Log.i(TAG,"★onRewardedVideoAdLoaded:");
}
// 広告再生時
@Override
public void onRewardedVideoStarted() {
Toast.makeText(this, "onRewardedVideoStarted", Toast.LENGTH_SHORT).show();
Log.i(TAG,"★onRewardedVideoStarted:");
}
// 動画内の広告へ移動する時
@Override
public void onRewardedVideoAdOpened() {
Toast.makeText(this, "onRewardedVideoAdOpened", Toast.LENGTH_SHORT).show();
Log.i(TAG,"★onRewardedVideoAdOpened:");
}
// 動画広告→リンク→ブラウザ などアプリから離れる時
@Override
public void onRewardedVideoAdLeftApplication() {
Toast.makeText(this, "onRewardedVideoAdLeftApplication", Toast.LENGTH_SHORT).show();
Log.i(TAG,"★onRewardedVideoAdLeftApplication:");
}
// 動画視聴完了後の報酬
@Override
public void onRewarded(RewardItem rewardItem) {
Toast.makeText(this, "YES! I GOT", Toast.LENGTH_SHORT).show();
Log.i(TAG,"★onRewarded:");
SET_TIME = SET_TIME + 5; //5sずつ加算
}
// 広告視聴完了時
@Override
public void onRewardedVideoCompleted() {
Toast.makeText(this, "onRewardedVideoCompleted", Toast.LENGTH_SHORT).show();
Log.i(TAG,"★onRewardedVideoCompleted:");
}
// 動画広告閉じた時
@Override
public void onRewardedVideoAdClosed() {
Toast.makeText(this, "広告視聴ありがとうございました", Toast.LENGTH_SHORT).show();
Log.i(TAG,"★onRewardedVideoAdClosed:");
loadRewardedVideoAd();
timer(SET_TIME);
}
// 動画広告読み込み失敗時
@Override
public void onRewardedVideoAdFailedToLoad(int i) {
Toast.makeText(this, "onRewardedVideoAdFailedToLoad", Toast.LENGTH_SHORT).show();
Log.i(TAG,"★onRewardedVideoAdFailedToLoad:");
}
}
このように処理することで、定期的にアプリ内で動画リワード広告を表示することが可能となります。
しかし実際のアプリ開発を想定すると、動画広告が終わる前に広告を閉じてしまうケースも考えられますね。 AdMob の広告掲載における報酬基準は少し複雑なようですが、おそらく広告をクリックしてもらう方が報酬増を見込めます。そこで動画広告を最後まで視聴したか・していないか、という判断要素をプログラムに加えて、 特典内容を編集してみました。
【広告最後まで見た場合】 次の動画広告再生まで + 5 秒
【広告最後まで見なかった場合】 次の動画広告再生まで -10 秒(ただしタイマー16秒以上の場合)
広告視聴の有無に応じた動画リワード広告のプログラム
画像クリックで拡大
編集後の MainActivity
// ライフサイクル ログチェック
// タイマー停まる
// 動画広告再生
// 動画広告視聴で、次回動画広告まで +Time、 動画広告消した場合は -Time(ただし Time > 16 のみ)
package com.oshimamasara.timer;
import android.os.CountDownTimer;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
import android.widget.Toast;
import com.google.android.gms.ads.AdRequest;
import com.google.android.gms.ads.MobileAds;
import com.google.android.gms.ads.reward.RewardItem;
import com.google.android.gms.ads.reward.RewardedVideoAd;
import com.google.android.gms.ads.reward.RewardedVideoAdListener;
public class MainActivity extends AppCompatActivity implements RewardedVideoAdListener {
private static final String TAG = "MainActivity";
TextView textView;
private CountDownTimer mCountDownTimer;
private static long SET_TIME=10;
private long timeRemaining;
private static final String AD_UNIT_ID = "ca-app-pub-3940256099942544/5224354917";
private static final String APP_ID = "ca-app-pub-3940256099942544~3347511713";
private RewardedVideoAd rewardedVideoAd;
boolean watchedVideo; //false
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.i(TAG,"★onCreate");
Log.i(TAG,"★真偽値チェック:デフォルトの真偽値は true or false ? "+watchedVideo);
textView = (TextView)findViewById(R.id.textView);
MobileAds.initialize(this, APP_ID);
rewardedVideoAd = MobileAds.getRewardedVideoAdInstance(this);///
rewardedVideoAd.setRewardedVideoAdListener(this);
loadRewardedVideoAd();
timer(SET_TIME);
}
private void timer(long time) {
watchedVideo = false;
mCountDownTimer = new CountDownTimer(time*1000, 1000) {
public void onTick(long millisUntilFinished) {
Log.i(TAG,"★millisUntilFinished "+millisUntilFinished);
timeRemaining=millisUntilFinished/1000;
textView.setText("seconds remaining: " + timeRemaining);
}
public void onFinish() {
textView.setText("done!");
// show ad
showRewardedVideo();
Log.i(TAG,"★終了");
}
}.start();
}
private void loadRewardedVideoAd() {
if (!rewardedVideoAd.isLoaded()) {
rewardedVideoAd.loadAd(AD_UNIT_ID, new AdRequest.Builder().build());
}
}
private void showRewardedVideo() { ///
//textView.setVisibility(View.INVISIBLE);
if (rewardedVideoAd.isLoaded()) {
rewardedVideoAd.show();
}
}
@Override
protected void onStart(){
super.onStart();
Log.i(TAG,"★onStart");
Toast.makeText(this, "スタート!", Toast.LENGTH_SHORT).show();
}
@Override
protected void onResume(){
super.onResume();
Log.i(TAG,"★onResume");
}
@Override
protected void onPause(){
super.onPause();;
Log.i(TAG,"★onPause");
}
@Override
protected void onStop(){
super.onStop();
Log.i(TAG,"★onStop");
mCountDownTimer.cancel();
}
@Override
protected void onRestart(){
super.onRestart();
Log.i(TAG,"★onRestart");
timer(timeRemaining);
}
@Override
protected void onDestroy(){
super.onDestroy();
Log.i(TAG,"★onDestroy");
}
// TEXT https://developers.google.com/android/reference/com/google/android/gms/ads/reward/RewardedVideoAdListener
// 動画広告の準備完了時
@Override
public void onRewardedVideoAdLoaded() {
Toast.makeText(this, "onRewardedVideoAdLoaded", Toast.LENGTH_SHORT).show();
Log.i(TAG,"★onRewardedVideoAdLoaded:");
}
// 広告再生時
@Override
public void onRewardedVideoStarted() {
Toast.makeText(this, "onRewardedVideoStarted", Toast.LENGTH_SHORT).show();
Log.i(TAG,"★onRewardedVideoStarted:");
}
// 動画内の広告へ移動する時
@Override
public void onRewardedVideoAdOpened() {
Toast.makeText(this, "onRewardedVideoAdOpened", Toast.LENGTH_SHORT).show();
Log.i(TAG,"★onRewardedVideoAdOpened:");
}
// 動画広告→リンク→ブラウザ などアプリから離れる時
@Override
public void onRewardedVideoAdLeftApplication() {
Toast.makeText(this, "onRewardedVideoAdLeftApplication", Toast.LENGTH_SHORT).show();
Log.i(TAG,"★onRewardedVideoAdLeftApplication:");
}
// 動画視聴完了後の報酬
@Override
public void onRewarded(RewardItem rewardItem) {
Toast.makeText(this, "YES! I GOT", Toast.LENGTH_SHORT).show();
Log.i(TAG,"★onRewarded:");
watchedVideo = true;
SET_TIME = SET_TIME + 5; //5sずつ加算
}
// 広告視聴完了時
@Override
public void onRewardedVideoCompleted() {
Toast.makeText(this, "onRewardedVideoCompleted", Toast.LENGTH_SHORT).show();
Log.i(TAG,"★onRewardedVideoCompleted:");
}
// 動画広告閉じた時
@Override
public void onRewardedVideoAdClosed() {
Toast.makeText(this, "広告視聴ありがとうございました", Toast.LENGTH_SHORT).show();
Log.i(TAG,"★onRewardedVideoAdClosed:");
loadRewardedVideoAd();
Log.i(TAG,"★真偽値チェック onRewardedVideoAdClosed/if文入る前: "+ watchedVideo); //true
if(watchedVideo){
Toast.makeText(this, "アプリ視聴時間が延びました", Toast.LENGTH_SHORT).show();
Log.i(TAG,"★真偽値チェック onRewardedVideoAdClosed/if文: "+ watchedVideo);
timer(SET_TIME);
} else if(watchedVideo==false && SET_TIME < 16){
Toast.makeText(this, "広告視聴で閲覧時間UP", Toast.LENGTH_SHORT).show();
Log.i(TAG,"★真偽値チェック onRewardedVideoAdClosed/else if文: "+ watchedVideo);
timer(SET_TIME);
} else {
Toast.makeText(this, "広告視聴で閲覧時間UP", Toast.LENGTH_SHORT).show();
Log.i(TAG,"★真偽値チェック onRewardedVideoAdClosed/else文: "+ watchedVideo);
SET_TIME = SET_TIME - 10;
timer(SET_TIME);
}
}
// 動画広告読み込み失敗時
@Override
public void onRewardedVideoAdFailedToLoad(int i) {
Toast.makeText(this, "onRewardedVideoAdFailedToLoad", Toast.LENGTH_SHORT).show();
Log.i(TAG,"★onRewardedVideoAdFailedToLoad:");
}
}
// ユーザーのデータ保存 インターフェース: PreferenceManager など
まず動画広告を最後まで見たかどうかという判断は、 onRewarded() 内の watchedVideo = true で判断。広告を最後まで見なかった場合は、 onRewarded() が稼働しませんので watchedVideo の真偽値は、デフォルトの false。
そしてその真偽値をもとに、動画広告が閉じられた時の処理内容を分岐。
- もし動画広告を最後まで見れば(watchedVideo = true)、ボーナス付与
- もし動画広告を最後まで見ていなければ(watchedVideo = false) 、マイナスのボーナス
プログラムを書くとこんな感じですね。
if(watchedVideo){
Toast.makeText(this, "アプリ視聴時間が延びました", Toast.LENGTH_SHORT).show();
timer(SET_TIME);
} else {
Toast.makeText(this, "アプリ視聴時間が減りました", Toast.LENGTH_SHORT).show();
SET_TIME = SET_TIME - 10;
timer(SET_TIME);
}
今回の場合は、初期設定時刻が 10s のため、上記プログラムにもう一段階条件を設けた内容にしてみました。
実際に上記プログラムのアプリを動かしてみると、動画広告視聴によって閲覧時間が延び、アプリを非表示とした際はタイマーが止まり、そして再びアプリを表示するとタイマーが稼働。ちょっとテレビコマーシャルのような感覚で、アプリが動くことが確認できます。
最後に、動画リワード広告をテスト用から本番用に変更しようと思うと、まずは Google Play にアプリをリリースする必要があります。アプリを公開しておかないと、 AdMob にアプリをセットできません。そして AdMob から本番用の ID をゲットできたら、プログラム内の ID を書き直して、再びリリースします。こうすることで本番用の動画リーワードを再生できます。
尚、今回はユーザーの同意無しで、自動的に動画リワードが再生されるプログラムとしました。AdMob の利用規約によれば、動画広告の前に、広告視聴で何を得られれるか明示する必要がある、と書かれています。今回紹介した機能を使う際は、事前にユーザーに同意を促す処理が必要となるでしょう。
\Webサイト担当者としてのスキルが身に付く!!/
まとめ
今回は動画リワード広告のみを実装したアプリのご紹介でしたが、成功している動画リワード広告採用のアプリを見てみると「課金で広告非表示」の機能も組み合わせたハイブリッド型のアプリが目立ちます。
広告だけの機能、課金だけの機能、タイマーだけの機能、といった単発的な機能装備に関する情報は見かけますが、それらを組み合わせたチュートリアルは少ないもの。しかし具体的なアプリ戦略を考えた際、複数の機能を掛け合わせるというのは必須項目でしょう。
「このプログラム内の値、どうすれば扱えるようになるんだ?」「引数、難しすぎ、、、」とアプリ開発のモチベーションはあるものの、思うように開発が進まずイライラしている方もいらっしゃるのではないでしょうか。
ところで Java や Android Studio の基礎学習はお済みでしょうか?
一見遠回りに感じる Java や Android Studio の基礎学習ですが、 長い目で見ると必ずプラス。難解なプログラムにぶち当たった時も、基礎知識があれば少しずつ掘り下げて、難しいプログラムの理解・習得にきっと役立つと思います。
オンライン形式のプログラミングスクール CodeCamp では、 Java や Android アプリ開発に詳しい現役エンジニアが受講生をサポート。マンツーマンでレッスンを進めますので、自分の学習レベルに応じて効率よく Java や Android Studio を学んでいくことが可能。
現在 CodeCamp では「無料体験」 も随時行っていますので、ご興味ある方は公式ページより参考にしてみてくださいね。
- この記事を書いた人
- オシママサラ