【Flutter】Admobの導入(Provider・Null-Safty版)
公式ガイド
Flutter公式のgoogle_mobile_adsプラグインの構築手順になります。
※admob_flutterの導入手順ではありません。
公式のガイドはこちら
前提確認
Flutterバージョン確認
・Flutter 1.22.0 以降であること
以下コマンドを実行し確認
% flutter --version
Flutter 2.0.5 • channel stable • https://github.com/flutter/flutter.git
Framework • revision adc687823a (7 months ago) • 2021-04-16 09:40:20 -0700
Engine • revision b09f014e96
Tools • Dart 2.12.3
Android Studioのバージョン確認
・Android Studio 3.2 以降
左上の「Android Studio」のタブから「About Android Studio」を選択し確認
Android用設定確認
・minSdkVersionを19以降に設定していること
・compileSdkVersionを28以降に設定していること
アプリレベルのbuild.gradleの以下の箇所を確認
android {
compileSdkVersion 30
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
}
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId ""
minSdkVersion 21
targetSdkVersion 30
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
}
Admobのプロジェクト作成
公式サイトにアクセスしてホームから「アプリの追加」を行う
プロジェクトの作成(Android・IOS共通)
以下手順をAndroid・IOSの2回分行う
①プラットフォームの設定
以下のように設定
※アプリがリリース済みの場合はストアに登録済みと設定
②アプリ名の設定
「アプリを追加」で設定は完了
※アプリ名はAndroid・IOSで同じにして構いません
③広告ユニットの設定
広告ユニットの作成をクリックし、作成したい広告ユニットを選択
④バーナー名を入力
※広告ユニット名はAndroid・IOSで同じにして構いません
ただし、プラットフォームごとに一意になるよう設定しましょう
⑤IDを控える
表示されたアプリIDと広告ユニットIDは後ほど使用するので控えておきましょう。
※後から確認も可能です。
Flutterプロジェクトの修正
Android用設定
「/android/app/src/main/AndroidManifest.xml」ファイルの
「application」タグ配下に「meta-data」タグを追加
※「android:value」には先ほど取得したAndroid用のアプリIDを設定する
<manifest>
<application>
〜〜〜
<meta-data
android:name="com.google.android.gms.ads.APPLICATION_ID"
android:value="ca-app-pub-xxxxxxxxxxxxxxxx~yyyyyyyyyy"/>
<application>
<manifest>
iOS用設定
「ios/Runner/Info.plist」ファイルに以下定義を追加
※「string」には先ほど取得したiOS用のアプリIDを設定する
<key>GADApplicationIdentifier</key>
<string>ca-app-pub-################~##########</string>
pubspec.yamlの編集
以下サイトを参考にプラグインの追加を行う
Admobの初期化処理(動作確認)
main.dartのmain関数内に以下の処理を追加する
実行し動作確認を行う。
import 'package:google_mobile_ads/google_mobile_ads.dart';
import 'package:flutter/material.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
MobileAds.instance.initialize();
runApp(MyApp());
}
広告表示実装(Model層)
公式のサンプルソースは以下を参照
広告表示用のModelクラスの作成
import 'dart:io';
import 'package:google_mobile_ads/google_mobile_ads.dart';
class AdManager {
BannerAd? bannerAd;
InterstitialAd? interstitialAd;
}
広告ユニットID取得用のメソッドを定義
IOSとAndroidで使用する広告ユニットIDが異なるため、上記で作成したAdManager内にPlatformを判別し、IDを判別するための関数を定義する。
※テストの段階ではテスト広告用のIDを使用してください。
Android
IOS
String get bannerAdUnitId {
if (Platform.isAndroid) {
//テスト広告
return "ca-app-pub-3940256099942544/6300978111";
} else if (Platform.isIOS) {
//テスト広告
return "ca-app-pub-3940256099942544/2934735716";
} else {
throw new UnsupportedError("Unsupported platform");
}
}
String get interstitialAdUnitId {
if (Platform.isAndroid) {
//テスト広告
return "ca-app-pub-3940256099942544/1033173712";
} else if (Platform.isIOS) {
//テスト広告
return"ca-app-pub-3940256099942544/4411468910";
} else {
throw new UnsupportedError("Unsupported platform");
}
}
Admob・広告ユニット初期化用のメソッドを定義する
上記で作成したAdManager内にAdmobの初期化処理(動作確認)にて作成したAdmobの初期化処理(動作確認)を一部、AdManagerクラスに処理を移譲する。
また、Banner広告とInterstitial広告の初期化処理を定義する。
※Banner広告はAdSizeのメソッドで表示するサイズを調整可能
※adLoadCallbackメソッドを定義することで、初期化のイベントをトリガーに行いたい処理を定義できる。
Future<void> initAdmob() {
return MobileAds.instance.initialize();
}
void initBannerAd() {
bannerAd = BannerAd(
adUnitId: bannerAdUnitId,
size: AdSize.fullBanner,
request: AdRequest(),
listener: BannerAdListener());
}
void initInterstitialAd() {
InterstitialAd.load(
adUnitId: interstitialAdUnitId,
request: AdRequest(),
adLoadCallback: InterstitialAdLoadCallback(
onAdLoaded: (InterstitialAd ad){
interstitialAd = ad;
_numInterstitialAdLoadAttempt = 0;
},
onAdFailedToLoad: (LoadAdError error){
print('InterstitialAd failed to load: $error');
interstitialAd = null;
_numInterstitialAdLoadAttempt++;
if (maxFailedToAttempt >= _numInterstitialAdLoadAttempt) initInterstitialAd();
},
),);
}
広告ユニットの読み込み処理を定義
Banner広告とInterstitial広告の読み込みと破棄の処理を定義する。
これらの関数はView層でProvider経由で呼び出される。
void loadBannerAd() {
bannerAd?.load();
}
void dispose() {
bannerAd?.dispose();
}
void loadInterstitialAd() {
if (interstitialAd == null) return;
interstitialAd!.fullScreenContentCallback = FullScreenContentCallback(
onAdDismissedFullScreenContent: (InterstitialAd ad) {
ad.dispose();
initInterstitialAd();
},
onAdFailedToShowFullScreenContent: (InterstitialAd ad, AdError error) {
ad.dispose();
initInterstitialAd();
},
);
interstitialAd!.show();
interstitialAd = null;
}
作成したModel層の全文
import 'dart:io';
import 'package:google_mobile_ads/google_mobile_ads.dart';
import 'package:{AdManegerクラスのパス}/ad_manager.dart';
class AdManager {
BannerAd? bannerAd;
InterstitialAd? interstitialAd;
bool isInterstitialAdReady = false;
int maxFailedToAttempt = 3;
int _numInterstitialAdLoadAttempt = 0;
Future<void> initAdmob() {
return MobileAds.instance.initialize();
}
void initBannerAd() {
bannerAd = BannerAd(
adUnitId: bannerAdUnitId,
size: AdSize.fullBanner,
request: AdRequest(),
listener: BannerAdListener());
}
void initInterstitialAd() {
InterstitialAd.load(
adUnitId: interstitialAdUnitId,
request: AdRequest(),
adLoadCallback: InterstitialAdLoadCallback(
onAdLoaded: (InterstitialAd ad) {
interstitialAd = ad;
_numInterstitialAdLoadAttempt = 0;
},
onAdFailedToLoad: (LoadAdError error) {
print('InterstitialAd failed to load: $error');
interstitialAd = null;
_numInterstitialAdLoadAttempt++;
if (maxFailedToAttempt >= _numInterstitialAdLoadAttempt)
initInterstitialAd();
},
),
);
}
static String get appId {
if (Platform.isAndroid) {
return "ca-app-pub-################~##########";
} else if (Platform.isIOS) {
return "ca-app-pub-################~##########";
} else {
throw new UnsupportedError("Unsupported platform");
}
}
String get bannerAdUnitId {
if (Platform.isAndroid) {
//テスト広告
return "ca-app-pub-3940256099942544/6300978111";
} else if (Platform.isIOS) {
//テスト広告
return "ca-app-pub-3940256099942544/2934735716";
} else {
throw new UnsupportedError("Unsupported platform");
}
}
String get interstitialAdUnitId {
if (Platform.isAndroid) {
//テスト広告
return "ca-app-pub-3940256099942544/1033173712";
} else if (Platform.isIOS) {
//テスト広告
return"ca-app-pub-3940256099942544/4411468910";
} else {
throw new UnsupportedError("Unsupported platform");
}
}
void loadBannerAd() {
bannerAd?.load();
}
void dispose() {
bannerAd?.dispose();
}
void loadInterstitialAd() {
if (interstitialAd == null) return;
interstitialAd!.fullScreenContentCallback = FullScreenContentCallback(
onAdDismissedFullScreenContent: (InterstitialAd ad) {
ad.dispose();
initInterstitialAd();
},
onAdFailedToShowFullScreenContent: (InterstitialAd ad, AdError error) {
ad.dispose();
initInterstitialAd();
},
);
interstitialAd!.show();
interstitialAd = null;
}
}
ViewModel層の作成
コンストラクターでAdManagerを受け取り、各種初期化処理を行う。
また、広告のloadと破棄を行う関数を定義する。
import 'package:flutter/material.dart';
class ViewModel extends ChangeNotifier {
AdManager adManager;
ViewModel(this.adManager) {
adManager
..initAdmob()
..initBannerAd()
..initInterstitialAd();
}
void loadBannerAd() {
adManager.loadBannerAd();
}
void loadInterstitialAd() {
adManager.loadInterstitialAd();
}
void disposeAd() {
adManager.dispose();
}
Main関数の修正
今回はProviderライブラリを使用して、ViewModel層を作成する。
導入未済の場合は以下サイトを参考にpubspec.yamlを編集する。
※このタイミングで動作確認をするのがおすすめ
import 'package:{viewmodelクラスのパス}/viewmodel.dart';
import 'package:provider/provider.dart';
import 'package:flutter/material.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
runApp(ChangeNotifierProvider<ViewModel>(
create: (_) => ViewModel(prefs,AdManager()),
child: MyApp(),
));
}
Banner広告の表示
Banner広告の読み込み
build関数直下など、画面表示処理の前にViewModelに定義したloadBannerAdを呼び出す。
Widget build(BuildContext context) {
context.select((ViewModel avm) => avm.loadBannerAd());
return Scaffold(
Banner広告の表示
以下関数を定義し、好みの場所で広告配置を行う。
Widget _footerAdContent(BuildContext context) {
var bannerAd = context.select((ViewModel avm) => avm.adManager.bannerAd);
return bannerAd == null
? Container()
: Center(
child: Container(
width: bannerAd.size.width.toDouble(),
height: bannerAd.size.height.toDouble(),
child: AdWidget(
ad: bannerAd,
),
),
);
}
Interstitial広告の表示
戻る系のボタンなどのクリックイベントに合わせて、以下のように画面遷移前にViewModel層に定義した、loadInterstitialAdメソッドを呼び出しましょう。
onPressed: () {
context.read<AppViewModel>().loadInterstitialAd(null);
Navigator.of(context).pop(1);
},
Discussion