見出し画像

インターステンシャル広告をProviderパターンで実装してみた

この記事を見て、出来るようになること

(1)FutureBuilderを用いた初期化処理を実装できるようになる。
 ・初期化中の画面表示(InitializePage)
 ・初期化エラー時の画面表示(ErrorPage)
 ・完了時の画面表示(HomePage)

(2)インターステンシャル広告を任意のタイミングで表示できるようになる。
 この記事ではカウンターが5の倍数になったタイミングで表示

画面イメージ

フリマ一括検索アプリの操作方法.001

参考サイト

事前準備

1.providerパッケージを追加

flutter pub add provider

2.Google_mobile_adsパッケージを追加

flutter pub add google_mobile_ads

3.Info.plistに広告アプリIDを追加(xxxは各自のID)[for iOS]

<key>GADApplicationIdentifier</key>
<string>ca-app-pub-xxxxxxxxxxxxxxxx~xxxxxxxxxx</string>
<key>SKAdNetworkItems</key>
<array>
	<dict>
		<key>SKAdNetworkIdentifier</key>
		<string>cstr6suwn9.skadnetwork</string>
	</dict>
</array>

4.AndroidMafifest.xmlに広告アプリIDを追加(xxxは各自のID)[for Android]

<meta-data
   android:name="com.google.android.gms.ads.APPLICATION_ID"
   android:value="ca-app-pub-xxxxxxxxxxxxxxxx~xxxxxxxxxx"/>

広告モデルのクラスを作成

lib/model/ad_Interstitial.dart

ポイント
・ChangeNotifierをMixinする(notifyListeners()を使うため)
・カウンターが5で割り切れる時に広告を表示する(showAdメソッド)
・広告表示後、次の広告を作成する(createAdメソッド)

import 'package:flutter/cupertino.dart';
import 'dart:io';
import 'package:google_mobile_ads/google_mobile_ads.dart';

class AdInterstitial with ChangeNotifier{

 int num_of_attempt_load = 0;
 bool ready = false;


 int _counter = 0;

 int get counter => _counter;

 set counter(int value) {
   _counter = value;
   print(_counter);
   notifyListeners();

   if(_counter % 5 == 0){
     // カウンターが5で割り切れる場合は、広告を表示する
     showAd();
   }
   if(!ready){
     createAd();
   }
 }

 /**
  * バナー広告
  */
 InterstitialAd? _interstitialAd;
 InterstitialAd? get interstitialAd => _interstitialAd;
 set banner(InterstitialAd? value) {
   _interstitialAd = value;
   notifyListeners();
 }

 // create interstitial ads
 void createAd() {
   print("### 広告を作成します");
   InterstitialAd.load(
     adUnitId: interstitialAdUnitId,
     request: const AdRequest(),
     adLoadCallback: InterstitialAdLoadCallback(
       // 広告が正常にロードされたときに呼ばれます。
       onAdLoaded: (InterstitialAd ad) {
         print('### add loaded');
         _interstitialAd = ad;
         num_of_attempt_load = 0;
         ready = true;

         // 連続で広告を表示するためにロードされたら表示するようにする
         //showAd(); // showAdをcreateAdで呼び出す
       },
       // 広告のロードが失敗した際に呼ばれます。
       onAdFailedToLoad: (LoadAdError error) {
         num_of_attempt_load++;
         _interstitialAd = null;
         if (num_of_attempt_load <= 2) {
           createAd();
         }
       },
     ),
   );
 }

 // show interstitial ads to user
 Future<void> showAd() async {
   ready = false;
   if (_interstitialAd == null) {
     print('Warning: attempt to show interstitial before loaded.');
     return;
   }
   _interstitialAd!.fullScreenContentCallback = FullScreenContentCallback(
     onAdShowedFullScreenContent: (InterstitialAd ad) {
       print("ad onAdshowedFullscreen");
     },
     onAdDismissedFullScreenContent: (InterstitialAd ad) {
       print("ad Disposed");
       ad.dispose();
     },
     onAdFailedToShowFullScreenContent: (InterstitialAd ad, AdError aderror) {
       print('$ad OnAdFailed $aderror');
       ad.dispose();
       createAd();
     },
     onAdImpression: (InterstitialAd ad) => print('$ad impression occurred.'),
   );

   // 広告の表示には.show()を使う
   await _interstitialAd!.show();
   _interstitialAd = null;
 }

 // 広告IDをプラットフォームに合わせて取得
 static String get interstitialAdUnitId {
   if (Platform.isAndroid) {
     return '	ca-app-pub-3940256099942544/1033173712'; // android用のテスト広告ID(インターステンシャル)
   } else if (Platform.isIOS) {
     return 'ca-app-pub-3940256099942544/4411468910'; // ios用のテスト広告ID(インターステンシャル)
   } else {
     //どちらでもない場合は、テスト用を返す
     return BannerAd.testAdUnitId;
   }
 }
}

main.dartを修正

import 'dart:io';

import 'package:flutter/material.dart';
import 'package:flutter_ad_test/model/ad_Interstitial.dart';
import 'package:google_mobile_ads/google_mobile_ads.dart';
import 'package:provider/provider.dart';
import 'package:flutter/services.dart';

void main() {
 runApp(MyApp());
}

class MyApp extends StatelessWidget {

 late AdInterstitial adInterstitial;

 /**
  * 初期処理
  */
 Future<void> _initializeApp(BuildContext context) async {
   WidgetsFlutterBinding.ensureInitialized();
   MobileAds.instance.initialize();

   adInterstitial = AdInterstitial();
   adInterstitial.createAd(); // 初回広告を作成しておく
   await Future.delayed(const Duration(milliseconds: 1000));// ダミー処理(初期化中の画面の動作確認のため)
   // throw Exception("初期化処理エラー(ダミー)"); // 起動エラー発生時の動作確認用
 }

 @override
 Widget build(BuildContext context) {
 return FutureBuilder(
   future: _initializeApp(context),
   builder: (BuildContext context, AsyncSnapshot<dynamic> snapshot) {
     if(snapshot.hasError){
       // エラー発生時に表示するウィジェット
       return ErrorPage(message: snapshot.error!.toString());
     }
     if (snapshot.connectionState == ConnectionState.done) {
       // _initializeApp完了後に表示するウィジェット
       return MultiProvider(
         providers: [
           ChangeNotifierProvider(
             create: (_) => adInterstitial,
           ),
         ],
         child: HomePage(),
       );
     }
     // _initializeApp処理中に表示するウィジェット
     return InitializePage();
   },

 );
 }

}


class InitializePage extends StatelessWidget {
 String title = "Initializing...";

 @override
 Widget build(BuildContext context) {
   return MaterialApp(
     debugShowCheckedModeBanner: false, // 右上に表示される"debug"ラベルを消す
     home: Scaffold(
       body: Container(
         child: Center(
           child: Column(
             mainAxisSize: MainAxisSize.min,
             children: <Widget>[
               Text(title),
             ],
           ),
         ),
       ),

     ),
   );
 }
}

class HomePage extends StatelessWidget {
 @override
 Widget build(BuildContext context) {

   return MaterialApp(
     debugShowCheckedModeBanner: false, // 右上に表示される"debug"ラベルを消す
     home: Consumer<AdInterstitial>(
         builder: (ctx, model, child) {

           return Scaffold(
             appBar: AppBar(
               title: Text("インターステンシャル広告のデモ"),
             ),

             body: Center(
               child: Column(
                 mainAxisAlignment: MainAxisAlignment.center,
                 children: <Widget>[
                   const Text(
                     '5の倍数でインターステンシャル広告が表示されます',
                   ),
                   Text(
                     model.counter.toString(),
                     style: Theme.of(context).textTheme.headline4,
                   ),
                 ],
               ),
             ),
             floatingActionButton: FloatingActionButton(
               onPressed: (){
                 model.counter++;
               },
               child: const Icon(Icons.add),
             ),
           );
         }),
   );
 }
}


class ErrorPage extends StatelessWidget {
 final String? message;

 String title = "予期しないエラーが発生しました";
 ErrorPage({Key? key, required this.message}) : super(key: key);

 @override
 Widget build(BuildContext context) {
   return MaterialApp(
     debugShowCheckedModeBanner: false, // 右上に表示される"debug"ラベルを消す
     home: Scaffold(
       appBar: AppBar(
         title: Text("インターステンシャル広告のデモ"),
       ),

       body: Container(
         padding: EdgeInsets.all(10),
         child: Column(
           mainAxisAlignment: MainAxisAlignment.start,
           crossAxisAlignment: CrossAxisAlignment.start,
           children: <Widget>[
             Text(
               title,
               style: Theme.of(context).textTheme.headline6,
             ),
             Text(
               message ?? "",
               style: Theme.of(context).textTheme.bodyText2,
             ),
           ],
         ),
       ),
       floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
       floatingActionButton: FloatingActionButton.extended(
         onPressed: ()async{
           String msg = title + "\n";
           msg = msg + message! + "\n";
           final data = ClipboardData(text: msg);
           await Clipboard.setData(data);
         },
         icon: const Icon(Icons.copy),
         label: Text("メッセージをコピーする"),
       ),
     ),
   );
 }


}

補足

・InitializePageを表示するために、初期化処理で以下の遅延を入れています。実際の開発では不要です。(あくまでもデバック用)

await Future.delayed(const Duration(milliseconds: 1000));// ダミー処理(初期化中の画面の動作確認のため)

・初期化エラー時の画面を確認する場合は、以下の処理を有効にしてください。(コメントを外してください)

// throw Exception("初期化処理エラー(ダミー)"); // 起動エラー発生時の動作確認用


この記事が気に入ったらサポートをしてみませんか?