【はじめてのAndroidアプリ開発】バナー広告を課金で削除する方法


【はじめてのAndroidアプリ開発】バナー広告を課金で削除する方法

Androidのアプリ開発をはじめようと考えている方、もしくははじめたばかりの方向けにお届けしている 【はじめてのAndroidアプリ開発】 シリーズ。 今回は 『バナー広告を課金で非表示にする』方法のご紹介。

バナー広告の設定方法からアプリ内課金の設定方法、そしてアプリのリリース方法など一連の流れをご紹介していきます。

★本稿はこんな方に役立ちます★

  • Android アプリ開発初心者
  • Android アプリで一儲けしたい方
  • Javaをもっと知りたい方

★開発環境★

・ Android Studio 3.4
・ Java
・ 実機テスト
・ バナー広告は AdMob を利用
・ アプリ内課金は Google Play Console を利用
・ アプリ内課金のメソッドは Android純正の Billingライブラリ(バージョン 1系)
・ テスト課金と実課金を実行
目次
  1. 課金とバナー広告削除の学習を始める前に知っておきたいこと
  2. バナー広告を課金で削除するするために必要な環境
  3. バナー広告を課金で削除できるアプリを作る様子
  4. 学習時の注意点
  5. Androidアプリ内課金の学習に役立つページ
  6. 課金でバナー広告を削除できるアプリを作ってみよう
  7. 【バナー広告を課金で削除する方法】バナー広告の設置
  8. 【バナー広告を課金で削除する方法】バナー広告の非表示方法
  9. 【バナー広告を課金で削除する方法】課金機能の設定
  10. 【バナー広告を課金で削除する方法】課金後は広告非表示
  11. バナー広告を課金で消すプログラムの内容
  12. バナー広告をテスト用から本番用に変更する方法
  13. まとめ

課金とバナー広告削除の学習を始める前に知っておきたいこと

バナー広告を課金で削除するするために必要な環境

image

  • Android Studio
  • Google Play Consoleのアカウント
  • 実機

Google Play Console のアカウントと実機は、課金アイテムを登録するために必要となります。バナー広告については、サンプルの ID を使えば AdMob に登録していなくてもバナー広告を表示することが可能。

尚、アプリ内に特定のバナーを表示するためには、公開されたアプリが事前に必要となってきます。なのでアプリを作ったからといって、すぐに収益可能なバナー広告が表示できるというわけではありませんので、焦らずにじっくりと開発を進めていく心構えが必要でしょう。

バナー広告を課金で削除できるアプリを作る様子

【プログラミング初心者向けに工夫した点】

  • 編集する Javaプログラムは MainActivity.java のみ
  • 課金で広告を非表示にするためだけの必要最低限の機能
  • アプリ内課金が初めての方でも操作手順を理解できるように、署名付き APK ファイルの作成方法も収録
  • ざっくりとしたプログラムの紹介

動画を見たり、実際に公開されているアプリをインストールして使ってみたり、コードを Android Studio にインポートして確認してみたり、色々触っていく中でアプリ内課金やバナー広告の表示・非表示の感覚をつかめるようになると思います。焦らずに、じっくり、ひとつずつ理解していくように頑張りましょう。

学習時の注意点

image

バナー広告を課金で非表示にする方法の公式チュートリアルはありません。公開されているコードや個人で紹介している YouTube の動画、それからブログ記事といったものを参考に課金でバナー広告を非表示にする方法を習得する必要があります。

実際に私もいくつかのチュートリアルを参考にプログラムを実際に動かしてみたり、コードを確認してみました。その中でこれから課金機能を学習しようと考えている方にとって事前にしておいた方がいい情報がありましたので、ご紹介させていただきます。

  • ライブラリを使うかどうか
  • 終了するインターフェース
  • APIの更新
  • 様々なアプローチ方法

ライブラリを使うかどうか

最初のうちはアプリ開発で課金を扱うの少し難しいですよね。そんな時役に立つのが課金対応のライブラリである「Android In-app Billing Version 3」。 Android に標準で用意されている Billing API に比べると、必要なメソッドを一瞬で用意でき、取り扱いが難しい購入履歴のデータ取得も比較的容易に取り扱うことができます。

しかし便利な反面、ライブラリが定期的にメンテナンスされていないと、ライブラリ内のプログラムが古くなっている可能性もあります。 上記 Android In-app Billing Version 3 の例では、 2年ほどメンテナンスされていない様子*。 今後メンテナンスされるかどうかわからないこともありますので、ひょっとすると Android バージョン更新に伴って、ライブラリでの課金処理ができなくなる可能性も考えられます。

Android に限った話ではありませんが、ライブラリを利用する際はプログラムのアップデート状況、それからライブラリを利用するプラットフォームの変動状況などを踏まえて利用することをお勧めしますね。以上のことより今回は便利そうな課金ライブラリ「Android In-app Billing Version 3」 を使わないこととしました。

終了するインターフェース

image

img: YouTube/Google I/O 2109

ネットで Android のアプリ内課金の情報収集をした際、AIDL(Android インターフェース定義言語)というインターフェースを利用したチュートリアルをよく見ました。情報量もあって使いやすそうな AIDL ですが、なんと 2021年に機能しなくなるそう。代わりにアプリ内課金をサポートする Billing ライブラリを使ってくださいとのこと。

ちなみに今使われている Billing ライブラリのバージョン 1 と 2 も 2021年には終了し、バージョン 3、バージョン 4 への対応が必要予定。アプリ内課金はこれから Billingライブラリが主体となりますので、間違って AIDL を学習しないように注意しときたいですね。

公式ライブラリ「Billingライブラリ」の更新

現在 Android のアプリ内課金は、 Billing ライブラリが推奨されています。ネット上でも Billing ライブラリを使用したチュートリアルが多数存在しますが、 そのライブラリのバージョンは 1系。しかし、 2019年5月7日に Google Play Billing Library 2.0 がリリース。 変更点はいくつかあるものの、プログラミング的に影響があるのは課金アイテムの取り扱い setSku() が使えなくなったこと。

Billing Library 1系では課金アイテムの処理に setSku() がよく登場してきましたが、 2 系では setSkuDetails() などを利用する必要が。 公式ドキュメントで setSkuDetails() の使い方紹介されていますが、ちょっと難しいです。そしてネット上でも今のところ Billing Library 2系 のチュートリアルはない状況。

Billing Library 1系と 2系では、「プログラムに違いが出る」ということを認識しておきましょう。

様々なアプローチ方法

image

課金・・バナー広告・・・・・ を削除」という二つの処理要素を考えた際、いくつかの実行方法が思いつくと思います。

例えば、ユーザーの購入履歴情報を取得し、該当商品を購入済みであれば広告を非表示にする方法。または課金の有無で真偽値をコントロールし、課金後は真として非表示にする方法。もしくは Billing ライブラリの処理工程の中に、広告表示・非表示のプログラムを書き込む方法。

この他にも「課金でバナー広告を削除する方法」 はいくつかあると思いますが、処理内容によってプログラムも変わってきます。そして当然、使用するクラスやインターフェイスなども変わり、難易度も違ってきますし、情報量も違います。

つまりアプリの構成や広告非表示の処理プロセスを理解し、適切な方法を選択する必要がありますね。今回は HelloWorldアプリにバナー広告を表示させ、そのバナー広告を削除するだけなので、一番簡単そうな

「Billingライブラリの処理工程の中に、広告表示・非表示のプログラムを書き込む」

を選択してみました。

Androidアプリ内課金の学習に役立つページ

image

今回はじめてアプリ内課金を体験される方は、おそらく本稿だけでは説明不十分と思います。色々なユースケースやプログラム処理を参考にすることによって理解が深まり、自分にとって使いやすい処理プログラムが見つかると思います。

アプリ内課金のチュートリアルはネット上に多数ありますが、参考となったチュートリアルをいくつかご紹介させていただきます。

課金でバナー広告を削除できるアプリを作ってみよう

image

今回は比較的処理が簡単な 「Billingライブラリーの処理工程の中に、広告表示・非表示のプログラムを書き込む」 という方法でアプリを作っていきたいと思います。 使用するファイルも Android Studio 起動時のデフォルトファイルのまま利用しますので、アプリ構造も分かりやすいと思いますよ。

【大まかな流れ】

  • バナー広告の設置
  • バナー広告の削除方法
  • 課金機能の搭載
  • 課金後は広告非表示

【各項目の内容】

  • バナー広告/テスト用のバナー
  • 課金テスト/テスト課金と実課金の両方
  • 課金アイテムのタイプ/ 単発商品(INAPP)
  • 表示・非表示の保存方法/ インターフェース: PreferenceManager

【バナー広告を課金で削除する方法】バナー広告の設置

image

まずはアプリ内にバナー広告を表示してみましょう。 Android Studio 起動し、新規プロジェクトの作成作業に入ります。

image

Empty Activity を選択。

image

今回はアプリ内課金の機能を利用するため、作成したアプリを Google Play Console にアップロードする必要があります。そのアップロードの際にパッケージネームがデフォルトの

com.example.○○○○ 

ではアップロードすることはできません。 example を任意の値に変更する必要があります。今回は、

com.oshimamasara.○○○○ 

としました。

image

新規プロジェクト作成後、グラドルが安定したらまずはバナー広告の表示設定から作業していきます。バナー広告の表示方法は以前にもご紹介した 「【はじめてのAndroidアプリ開発】バナー広告の設定」 が参考になると思います。今回は Google デベロッパーの公式ドキュメントを参考にバナー広告の設定を進めていきました。

まずは build.gradle(アプリレベル) に必要な SDK の読み込み設定を行います。

【追加するコード】

implementation 'com.google.android.gms:play-services-ads:17.2.0'
編集後の build.gradle のコード

apply plugin: 'com.android.application'

android {
    compileSdkVersion 28
    defaultConfig {
        applicationId "com.oshimamasara.billingremovead001"
        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.0'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test🏃1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}

image

次は AdMob を利用するために必要なコードをマニフェストに追記します。追記する場所は </application> の手前で、とりあえずはサンプルの ID を用いて AdMob を利用。

【追加するコード】

        <meta-data
            android:name="com.google.android.gms.ads.APPLICATION_ID"
            android:value="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.billingremovead001">

    <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:value="ca-app-pub-3940256099942544~3347511713"/>
    </application>

</manifest>

image

次は AdMob の広告を読み込む前に必要な「初期化作業」を MainActivity の中に設定します。

        // Sample AdMob app ID: ca-app-pub-3940256099942544~3347511713
        MobileAds.initialize(this, "ca-app-pub-3940256099942544~3347511713");
編集後の MainActivity のコード

package com.oshimamasara.billingremovead001;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import com.google.android.gms.ads.MobileAds;

public class MainActivity extends AppCompatActivity {

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

        // Sample AdMob app ID: ca-app-pub-3940256099942544~3347511713
        MobileAds.initialize(this, "ca-app-pub-3940256099942544~3347511713");
    }
}

image

次はバナー広告を表示するためのレイアウトを設定していきます。 activity_main.xml を開いて以下のコードを追記。

        <com.google.android.gms.ads.AdView
            xmlns:ads="http://schemas.android.com/apk/res-auto"
            android:id="@+id/adView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerHorizontal="true"
            android:layout_alignParentBottom="true"
            ads:adSize="BANNER"
            ads:adUnitId="ca-app-pub-3940256099942544/6300978111">
        </com.google.android.gms.ads.AdView>
編集後の activity_main のコード

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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: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" />

    <com.google.android.gms.ads.AdView
        xmlns:ads="http://schemas.android.com/apk/res-auto"
        android:id="@+id/adView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_alignParentBottom="true"
        ads:adSize="BANNER"
        ads:adUnitId="ca-app-pub-3940256099942544/6300978111">
    </com.google.android.gms.ads.AdView>


</RelativeLayout>

コードを追加すると、プレビュー画面にバナー広告用スペースが設けられたことが確認できると思います。

image

以下のコードを追加することでテスト用のバナー広告を表示することができます。

private AdView mAdView;
        mAdView = findViewById(R.id.adView);
        AdRequest adRequest = new AdRequest.Builder().build();
        mAdView.loadAd(adRequest);
編集後の MainActivity のコード

package com.oshimamasara.billingremovead001;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import com.google.android.gms.ads.MobileAds;
import com.google.android.gms.ads.AdRequest;
import com.google.android.gms.ads.AdView;
public class MainActivity extends AppCompatActivity {
    private AdView mAdView;

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

        // Sample AdMob app ID: ca-app-pub-3940256099942544~3347511713
        MobileAds.initialize(this, "ca-app-pub-3940256099942544~3347511713");
        mAdView = findViewById(R.id.adView);
        AdRequest adRequest = new AdRequest.Builder().build();
        mAdView.loadAd(adRequest);
    }
}

コードを追加できたら早速エミュレーターを起動して、バナー広告が表示されているかチェックしてみましょう。

次はこの表示されたバナー広告を非表示にする方法をご紹介していきます。

【バナー広告を課金で削除する方法】バナー広告の非表示方法

image

表示内容を消したり非表示にする方法はいくつかあると思いますが、簡単なのは setVisibility()メソッドでしょう。以下のコードを追加するだけで、バナー広告を画面上から消すことができます(上図参照)。

mAdView.setVisibility(View.GONE);
編集後の MainActivity のコード

// バナー広告非表示
package com.oshimamasara.billingremovead001;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;

import com.google.android.gms.ads.MobileAds;
import com.google.android.gms.ads.AdRequest;
import com.google.android.gms.ads.AdView;
public class MainActivity extends AppCompatActivity {
    private AdView mAdView;

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

        // Sample AdMob app ID: ca-app-pub-3940256099942544~3347511713
        MobileAds.initialize(this, "ca-app-pub-3940256099942544~3347511713");
        mAdView = findViewById(R.id.adView);
        AdRequest adRequest = new AdRequest.Builder().build();
        mAdView.loadAd(adRequest);
        mAdView.setVisibility(View.GONE);
    }
}

mAdView.setVisibility(View.GONE); を追加した際に以下のようなポップアップが表示されるかもしれません。慌てずにポップアップ表示されている内容に従って設定を処理しておきましょう。

【コード追加時に表示されるポップアップケース その①】

image

この場合は OK ボタンをクリックしておきましょう。

【コード追加時に表示されるポップアップケース その②】

image

この場合は Alt + Enter キー で必要なクラスを追加しておきましょう。

mAdView.setVisibility(View.GONE); のコード追加後、エミュレーターを再度実行してみるとバナー広告が消えていることが確認できると思います。

これでバナー広告を表示したり非表示にしたりすることができるようになりましたので、後は制御文を作成して、課金状況に合わせた設定ができれば OK でしょう。

【バナー広告を課金で削除する方法】課金機能の設定

image

今回は『広告消すボタン』をタップすると支払い画面に進む、という流れにしたいと思いますので、まずは『広告消す』ボタンを作成します。

以下のコードを activity_main.xml に追加してみましょう。

    <Button
        android:id="@+id/buyButton"
        android:layout_width="wrap_content"
        android:layout_height="38dp"
        android:layout_above="@+id/adView"
        android:layout_alignParentEnd="true"
        android:layout_alignParentRight="true"
        android:layout_marginEnd="10dp"
        android:layout_marginRight="10dp"
        android:layout_marginBottom="10dp"
        android:text="@string/button"
        tools:ignore="MissingConstraints"
        tools:layout_editor_absoluteX="168dp"
        tools:layout_editor_absoluteY="437dp" />
編集後の activiti_main のコード

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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: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" />

    <com.google.android.gms.ads.AdView
        xmlns:ads="http://schemas.android.com/apk/res-auto"
        android:id="@+id/adView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_alignParentBottom="true"
        ads:adSize="BANNER"
        ads:adUnitId="ca-app-pub-3940256099942544/6300978111">
    </com.google.android.gms.ads.AdView>

    <Button
        android:id="@+id/buyButton"
        android:layout_width="wrap_content"
        android:layout_height="38dp"
        android:layout_above="@+id/adView"
        android:layout_alignParentEnd="true"
        android:layout_alignParentRight="true"
        android:layout_marginEnd="10dp"
        android:layout_marginRight="10dp"
        android:layout_marginBottom="10dp"
        android:text="@string/button"
        tools:ignore="MissingConstraints"
        tools:layout_editor_absoluteX="168dp"
        tools:layout_editor_absoluteY="437dp" />

</RelativeLayout>

コードを追加すると、プレビュー画面にボタンが表示されたことを確認できると思います。しかし、追加コードの中で一か所赤色エラーが発生。 これは文字列のファイル内にテキストが存在しないため。

strings.xml を開いて以下のコードを追加しておきましょう。

    <string name="button">広告消す</string>
    <string name="pref_ad_removal_purchased">購入済み</string>
    <string name="pref_remove_ads_key">adfree</string>
    <string name="billing_connection_failure">error</string>
編集後の strings.xml のコード

<resources>
    <string name="app_name">課金で広告消す例</string>
    <string name="button">広告消す</string>
    <string name="pref_ad_removal_purchased">購入済み</string>
    <string name="pref_remove_ads_key">adfree</string>
    <string name="billing_connection_failure">error</string>
</resources>

上記コードでは、今回のエラー対象であるテキスト以外に、これから登場してくる文字列の設定も合わせて行なっています。

strings.xml にコードを追加したら、改めて activity_main.xml を開いてエラーが消えていることを確認しておきましょう。



image

次はアプリ内課金を利用するために必要な SDK の設定を行います。下記コードを build.gradle(アプリレベル)に追加しましょう。

implementation 'com.android.billingclient:billing:1.1'
編集後の build.gradle(アプリレベル) のコード

apply plugin: 'com.android.application'

android {
    compileSdkVersion 28
    defaultConfig {
        applicationId "com.oshimamasara.billingremovead"
        minSdkVersion 15
        targetSdkVersion 28
        versionCode 3
        versionName "3.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.0'
    implementation 'com.android.billingclient:billing:1.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'
}

今回は billing ライブラリのバージョン1系を利用。バージョン2系が最新になりますが、課金アイテムの取得方法(setSku())がバージョン1と 2では異なりますので、チュートリアルが豊富な バージョン 1 を選択しました。バージョン 1 も 2 もサポートの終了期限は、2021年と同じ予定です。

image

次はアプリ内課金できるように、 MainActivity のプログラムを編集していきます。とりあえず課金機能のみテストしたかったので、一旦バナー広告を表示しないように上記のようにコードをまとめてみました。

image

アプリ内課金を実行できるように、上図のように MainActivity のプログラムを書き換えましょう。

アプリ内課金をテストする MainActivity のコード

// 決済機能のみ
package com.oshimamasara.billingremovead001;

import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

import com.android.billingclient.api.BillingClient;
import com.android.billingclient.api.BillingClientStateListener;
import com.android.billingclient.api.BillingFlowParams;
import com.android.billingclient.api.Purchase;
import com.android.billingclient.api.PurchasesUpdatedListener;
import com.google.android.gms.ads.MobileAds;
import com.google.android.gms.ads.AdRequest;
import com.google.android.gms.ads.AdView;

import java.util.List;

public class MainActivity extends AppCompatActivity implements PurchasesUpdatedListener {
    private AdView mAdView;
    private static final String TAG = "MainActivity";
    static final String ITEM_SKU_ADREMOVAL = "ad_remove_item";
    private Button mBuyButton;
    private BillingClient mBillingClient;

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

        MobileAds.initialize(this, "ca-app-pub-3940256099942544~3347511713");
        mAdView = findViewById(R.id.adView);

        mBillingClient = BillingClient.newBuilder(MainActivity.this).setListener(this).build();
        mBillingClient.startConnection(new BillingClientStateListener() {
            @Override
            public void onBillingSetupFinished(@BillingClient.BillingResponse int billingResponseCode) {
                if (billingResponseCode == BillingClient.BillingResponse.OK) {
                    // The billing client is ready. You can query purchases here.
                    Log.i(TAG,"BillingSetUpFinished:" + billingResponseCode); // 0  接続OK
                    Log.i(TAG,"アイテム:" + ITEM_SKU_ADREMOVAL);
                }
            }

            @Override
            public void onBillingServiceDisconnected() {
                //TODO implement your own retry policy
                Toast.makeText(MainActivity.this,  getResources().getString(R.string.billing_connection_failure), Toast.LENGTH_SHORT);
            }
        });

        mBuyButton = (Button) findViewById(R.id.buyButton);
        mBuyButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                BillingFlowParams flowParams = BillingFlowParams.newBuilder()
                        .setSku(ITEM_SKU_ADREMOVAL)
                        .setType(BillingClient.SkuType.INAPP)
                        .build();
                int responseCode = mBillingClient.launchBillingFlow(MainActivity.this, flowParams);
            }
        });
    }

    @Override
    public void onPurchasesUpdated(int responseCode, @Nullable List purchases) {

    }
}

MainActivity のプログラムを書き換えた際、下図のようなポップアップが表示されるかもしれません。

image

これは必要なクラスを読み込むために表示されていますので、 OK を押しておきましょう。

ここでエミュレーターを起動して、課金機能が実際に働いてるかどうかチェックしようとエミュレーターもしくは実機を起動しても、『広告消す』ボタン、反応はありません。 理由は、 課金アイテム ad_remove_item が Google Play Console に設定されていないため。(下図参照)

image

現段階のプログラムをテストしようと思うと、一旦この開発中のアプリを Google Play Console にアップロードする必要があります。そのためには開発中アプリを署名付き APK ファイルとして出力する必要がありますね。

image

署名付き APK ファイルの作成は Android Studio のツールバー Build から Generate Signed Bundle / APK... を選択します。 あとは下図を参考にキーの設定を行っていきましょう。

image

image

image

image

キーの保存先は現在作成しているアプリのトップ・ディレクトリを選択し、ファイル名は任意のものを入力、そしてファイル形式は .jks として作成します(上図)。

image

キーのパスワードなど必要な項目を入力し、OK。

image

NEXT。

image

Build の形式を release 、それからキー認証のバージョンを V1、V2 両方にチェックを入れ Finish。

image

APK の作成が完了したら Android Studio 画面右下に表示される locate をクリック。

image

すると release フォルダ内に APK ファイルが作成されたことが確認できます。今度はこの APK ファイルを Google Play Console にアップロードしていく必要が。


image

Google Play Console にアクセスし、 CREATE APPLICATION。

image

タイトルを入力し CREATE。なおこのタイトルは、アプリを公開した際に Google Play 上に表示されるタイトルとなります。 後で編集することも可能。

この後は Google Play にアップロードするアプリの説明書などの設定になりますので、手順が分からない方は動画を参考にしてみてください。 ページサイズの関係で画像添付は割愛させていただきました。

image

一通りアプリの基本情報が入力できたら、今度は APK ファイルをアップロードします。 アプリ内課金を利用する際の公開先は、ベータBeta版かアルファAlpha版が推奨。

今回は公開範囲の広いベータ版を利用して、アプリの設定を行っていきたいと思います。Beta欄の MANAGE ボタンをクリックしたら下図のように作業を進めていきましょう。

image

image

上図でアップロードする APK ファイルを指定します。

image

SAVE、そして Content rating と Pricing & distribution の項目を埋め、課金アイテムの登録作業を行ってきます。

image

左サイドバー内にある In-app products 内にある Managed products を選択。 そして CREATE MANAGED PRODUCT をクリック。

image

Product ID は、 MainActivity でセットした ad_remove_item をセット(上図参照)。

image

そして課金アイテムの情報を入力し、金額を決めたら保存。

image

これで公開(ベータ版)する準備が整いましたので、再び App releases を選択し、 Beta欄の MANAGE をクリック。

image

ベータ版を利用できるアカウントの数や連絡先などを設定し、保存。あとはボタンをクリックし、公開作業を進めていきます。

image

image

image

image

タイトル名の下に公開準備中が表示されていることが確認できます。

image

タイトル名の下が公開済みになると Google Play へのリンクが表示。 長くなりましたが、これで現在作成中のアプリで課金機能が有効になってるかどうかチェックすることができます。

課金機能のチェックについては、Google Play からアプリを実機にインストールしてチェックすることも出来ますし、実機を USB でパソコンに接続し、 Android Studio から実機を選択し、課金テストすることもできます。

【Google Play からインストールした様子】

image

上図の参考動画

『広告消す』ボタンをタップすると、支払画面に進み、決済が完了できることを確認できます。

画像クリックで拡大

現段階ではアプリ内課金を行うだけのプログラム内容となっていますので、支払いが完了しても『広告消す』ボタンの内容は変わりませんし、ボタンも表示されたままです。

「バナー広告を課金で非表示」 という目的を達成するためには、支払い前後で広告の表示・非表示を制御するプログラムを設定する必要がありますね。

【バナー広告を課金で削除する方法】課金後は広告非表示

image

課金後にバナー広告と『広告消す』ボタンを表示しないようにするために、 MainActivity を以下のように書き換えましょう(上図参照)。

課金後バナーとボタンを非表示にする MainActivity のコード

// バナー広告を課金で非表示 一応完成形
package com.oshimamasara.billingremovead;

import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

import com.android.billingclient.api.BillingClient;
import com.android.billingclient.api.BillingClientStateListener;
import com.android.billingclient.api.BillingFlowParams;
import com.android.billingclient.api.Purchase;
import com.android.billingclient.api.PurchasesUpdatedListener;
import com.google.android.gms.ads.AdRequest;
import com.google.android.gms.ads.AdView;
import com.google.android.gms.ads.MobileAds;

import java.util.List;

public class MainActivity extends AppCompatActivity implements PurchasesUpdatedListener {
    private static final String TAG = "MainActivity";
    static final String ITEM_SKU_ADREMOVAL = "ad_remove_item2"; // Product ID 一回のみ有効、再度課金テストする場合は ID 変更が必要
    private Button mBuyButton;
    private SharedPreferences mSharedPreferences;///////アプリ設定を保存するために必要
    private BillingClient mBillingClient;
    private AdView mAdView;


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

        MobileAds.initialize(this, "ca-app-pub-3940256099942544~3347511713");
        mAdView = findViewById(R.id.adView);

        mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);  // SharedPreferences() 購入の有無に関係するレイアウトを保存するため
        mBillingClient = BillingClient.newBuilder(MainActivity.this).setListener(this).build();
        mBillingClient.startConnection(new BillingClientStateListener() {
            @Override
            public void onBillingSetupFinished(@BillingClient.BillingResponse int billingResponseCode) {
                if (billingResponseCode == BillingClient.BillingResponse.OK) {
                    Log.i(TAG,"BillingSetUpFinished:" + billingResponseCode); // Logcatに出力 0  接続OK
                    Log.i(TAG,"アイテム:" + ITEM_SKU_ADREMOVAL);
                }
            }

            @Override
            public void onBillingServiceDisconnected() {
                Toast.makeText(MainActivity.this,  getResources().getString(R.string.billing_connection_failure), Toast.LENGTH_SHORT);
            }
        });

        // 広告消すボタンのイベント内容
        mBuyButton = (Button) findViewById(R.id.buyButton);
        mBuyButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                BillingFlowParams flowParams = BillingFlowParams.newBuilder()
                        .setSku(ITEM_SKU_ADREMOVAL)
                        .setType(BillingClient.SkuType.INAPP)
                        .build();
                int responseCode = mBillingClient.launchBillingFlow(MainActivity.this, flowParams); // launchBillingFlow()で下からビヨンと出る購入フローの表示
            }
        });


        queryPrefPurchases();
    }

    // アプリ再起動時に以前に支払いがあったかどうかチェック
    // 支払履歴なければ adFree = false で広告表示
    // 支払い履歴あれば adFree = true で広告非表示
    private void queryPrefPurchases() {
        Boolean adFree = mSharedPreferences.getBoolean(getResources().getString(R.string.pref_remove_ads_key), false);

        if (adFree) {
            // adFree = true の処理内容
            mBuyButton.setText(getResources().getString(R.string.pref_ad_removal_purchased));
            mBuyButton.setEnabled(false); // setEnabled ボタンイベント無効に
            mAdView.setVisibility(View.GONE);  // バナー広告非表示
            mBuyButton.setVisibility(View.GONE);  // ボタン非表示
        } else {
            AdRequest adRequest = new AdRequest.Builder().build();
            mAdView.loadAd(adRequest);  //広告表示
        }
    }


    //購入後のデータ書き換え onPurchasesUpdated() の処理に必要なプログラム
    private void handlePurchase(Purchase purchase) {
        if (purchase.getSku().equals(ITEM_SKU_ADREMOVAL)) {
            mSharedPreferences.edit().putBoolean(getResources().getString(R.string.pref_remove_ads_key), true).commit();
            mBuyButton.setVisibility(View.GONE);
            mAdView.setVisibility(View.GONE);
            mBuyButton.setText(getResources().getString(R.string.pref_ad_removal_purchased));   //ボタンの文字切り替え 購入済み
            mBuyButton.setEnabled(false);
        }
    }

    //購入手続き後のデータ書き換え
    @Override
    public void onPurchasesUpdated(int responseCode, @Nullable List purchases) {
        if (responseCode == BillingClient.BillingResponse.OK   //最初の購入フロー
                && purchases != null) {
            Log.i(TAG,"購入手続き完了後の処理::" + responseCode);
            for (Purchase purchase : purchases) {
                handlePurchase(purchase);
            }
        } else if (responseCode == BillingClient.BillingResponse.USER_CANCELED) {
            Log.d(TAG, "キャンセル時の処理::" + responseCode);
        } else if (responseCode == BillingClient.BillingResponse.ITEM_ALREADY_OWNED) {
            Log.i(TAG,"購入済みの場合の処理::" + responseCode);
            mSharedPreferences.edit().putBoolean(getResources().getString(R.string.pref_remove_ads_key), true).commit();
            mBuyButton.setVisibility(View.GONE);
            mAdView.setVisibility(View.GONE);mBuyButton.setText(getResources().getString(R.string.pref_ad_removal_purchased));
            mBuyButton.setEnabled(false);
        } else {
            Log.d(TAG, "例外時::" + responseCode);
        }
    }
}

本チュートリアルを見ながら実際にご自身でもアプリ内課金をテストしている方は、前章の【アプリ内課金のみテスト】で設定した Product ID と重複しないように注意する必要があります。 必要に応じてプログラム内の ITEM_SKU_ADREMOVAL 値を編集しましょう。

MainActivity の設定が完了したら、今度は APK ファイルを Google Play Console にアップロードしなくても、実機デバグで編集内容を確認することができます。課金アイテム購入後、 実際にバナー広告とボタンが消えるかテストしてみましょう。

【上記プログラムを実行した場合のアプリ画面の様子】

画像クリックで拡大


バナー広告を課金で消すプログラムの内容

画像クリックで拡大

アプリ内課金や Java プログラムを学習している方むけに、今回作成したプログラムの内容をご紹介させていただきます。

まずアプリが起動した際に読み込まれる onCreate() の内容については、

  • AdMob ID の読み込み(40、41行目)
  • Google Play Console への接続(44、45行目)
  • 『広告消す』ボタンのイベントスタンバイ(60行目)
  • 課金済みかどうかのチェック(queryPrefPurchases();)

初めてアプリをインストールし、アプリ起動後何もしない状態であれば 73行目の queryPrefPurchases() まで進みます。そしてその queryPrefPurchases() の中身は、

画像クリックで拡大

アプリ内課金がされていない状態であれば、80行目に示す通り

adFree = false

なので、82行目から始まる if文では else の内容が実行されます。つまりバナー広告が表示。

アプリインストール後、アプリを起動しただけでは、96行目と 108行目のメソッドは実行されません。

一度購入プロセスが完了し、支払い作業が終わると 108行目の onPurchasesUpdated() が実行されます。

画像クリックで拡大

onPurchasesUpdated()では、支払い手続き後の状態を BillingResponse で返してもらっています。

【支払い手続き後の状態】

  • BillingResponse.OK/支払い完了
  • BillingResponse.USER_CANCELED/キャンセルされた
  • BillingResponse.ITEM_ALREADY_OWNED/既に取得済みの商品でした

課金アイテムの購入手続き完了後に返ってくる BillingResponse の状態に合わせて if文で処理内容を制御。

無事購入が完了した場合は handlePurchases() が呼び出され、96行目から 104行目のプログラムが実行されます。この中ではバナー広告を非表示にしたりボタンを非表示に変更するプログラム(99から102行目)と 真偽値を変更するプログラム(98行目)が含まれています。

画像クリックで拡大

98行目の

mSharedPreferences.edit().putBoolean(getResources().getString(R.string.pref_remove_ads_key), true).commit();

によって真偽値が true に書き換えられています。その結果、アプリ内課金をした後にアプリを再起動した時、 再び 79行目の queryPrefPurchases(); が読み込まれ、 adFree = true を返し、広告が非表示となります。

この真偽値の変化については、 80行目の

Boolean adFree = mSharedPreferences.getBoolean(getResources().getString(R.string.pref_remove_ads_key), false);

の後に

Log.i(TAG,"adFreeの真偽値:" + adFree);

を追加し、アプリ内課金前の adFree の状態とアプリ内課金後、アプリを再起動した際の adFree の状態を確認すると真理値の変化を確認できると思います。

【アプリ内課金前】

画像クリックで拡大

【アプリ内課金後、アプリ再起動時】

画像クリックで拡大

以上の結果、課金したユーザーのみバナー広告を消すことができる設定となります。

またアプリをアンインストールして、再びインストールした場合、一旦はバナー広告とボタンが表示。しかし、『広告消す』ボタンをタップすると Google Play Console からその商品は既に取得済み、という情報が返されますので 118行目の BillingResponse.ITEM_ALREADY_OWNED) の処理が実行されて、すぐにバナー広告とボタンは非表示になります。

バナー広告をテスト用から本番用に変更する方法

ここまでご紹介して中で、表示されるバナー広告は全てテスト広告でした。実際に自分のアプリをリリースする際は、収益化されたバナー広告を表示すると思います。

テスト広告ではなく本当のバナー広告が表示されるかテストしてみましたので、その手順をご紹介させていただきますね。

【バナー広告を本番用にする手順】

  • 公開レベルをベータ版から本番用(Production)に変更
  • AndroidStudio にて build.gradle 内のバージョン名変更
  • APK再出力し、Google Play Console に APK を再アップロード
  • 2、3時間待ちます
  • AdMobにてアプリ登録
  • AdMob の ID を取得
  • MainActivity や AndroidManifest.xml 内の AdMob ID を変更
  • AndroidStudio にて build.gradle 内のバージョン名変更
  • APK再出力し、Google Play Console に APK を再アップロード
  • 1時間ほど待つとバナー広告が本番用に

ベータ版から本番用に公開レベルを変更する方法

image

まず Google Play Console にアクセスし、今回アプリ開発する中で作成したアプリを選択。そして左サイドバーにある Release management 内の App releases を選択し、ベータ版の Manage を選択。 そして上図の様に REMOVE TESTERS を選択し、テスト環境を無効にします。

image

そして今度はベータ版ではなく、本番用(Production)のアプリ公開手順を辿っていき、本番用としてアプリを公開。

ただ本番用にアプリを公開しようと思うと、再度 APK ファイルをアップロードする必要があります。その際以前にアップロードしたプロジェクトのバージョンと同じではエラーが。。。必要に応じて Android Studio 内の build.gradle(アプリ) ファイル内に存在するバージョンデータを書き換え、そして APK ファイルを出力し、 Google Play Console に再アップロードしましょう。

AdMobへのアプリ登録

image

AdMob にアクセスし、上図のように ADD APP を選択。すると公開してるアプリはあるかどうか聞かれますので YES を選択、下図のように開発者名、もしくは アプリ名を入力し、設定するアプリを選択します。

image

そして右側の ADD をクリックするとバナー広告に必要な AdMob の ID が取得できると思います。この ID を Android Studio で設定したテスト用 ID と置き換え。そして再び APK ファイル出力し Google Play Console に APK をアップロードすると収益可能なバナー広告が表示されると思います。

これでバナー広告による収益と課金による収益の ハイブリッド型収益モデル をアプリに搭載することができるでしょう。

AdMobと実機の Googleアカウントが同じ場合、本番用のバナー広告は表示されないと思います。他人のスマホで確認してみましょう。

以前に Googleアドセンスを利用していた場合、AdMob へスムーズにログインできません。Googleアドセンスに再アクセスし、設定状況を確認するか、AdMob用アカウントを作成しログインしましょう。

課金をテスト課金ではなく、実課金を実行しようと思うと、Google のアカウントが 「Google Play Console ≠ 実機」 である必要があります。ベータ版でアプリが公開できたら、誰か他人のスマホにベータ版アプリをインストールして試してみると、実課金を確認できると思います。ただし、実課金の場合は支払いが発生します。

Webサイト担当者としてのスキルが身に付く!!

無料カウンセリングはこちら

まとめ

今回は、バナー広告をアプリ内課金の処理プロセス内で非表示にする方法をご紹介しました。 RSS 系などのシンプルなアプリにはこうした処理プロセスでもそれほど問題ないかもしれませんが、その他のアプリ内課金を用意する場合は、今回のプログラムあまり適切ではないかもしれません。

また複数の画面からなる画面遷移を伴うアプリの場合は、バナー広告の表示・非表示のプログラムを MainActivity 内に記述するのではなく、専用のクラスを用意する方が適切と考えられます。

このようにちょっとアプリに応用を効かせようと思った時、やっぱり Java の基礎知識がないと正直シンドイと思います。

「儲かるアプリを作ってみたい」「Java を自由に使えるようになりたい」そう思った時、おそらく最短で最確な学習メソッドはプログラミングスクールでしょう。

オンライン形式でプログラミング学習をサポートする CodeCamp では、 Java をはじめ Androidアプリの基礎開発、 iPhoneアプリの基礎開発を学習することが可能。

少しお金はかかりますが、もし思ったようにアプリ開発が進んでいない場合は、

滞留時間コスト > スクールコスト

かもしれません。

現在 CodeCamp では無料体験や無料相談を行っていますので、ご興味ある方は公式ページよりチェックしてみてください。


関連記事

オシママサラ
この記事を書いた人
オシママサラ
まずは7日間お試し!人気プログラミング講座を無料公開中
オンライン・プログラミングレッスンNo.1のCodeCamp