🚨

【Flutter】Admobのバナーを複数箇所に出そうとした際に発生したエラーの解決策

2022/11/16に公開

現象

ListView内に一定間隔ごとにバナー広告を1つずつ設置しようとした際に以下のエラーが発生しました。

This AdWidget is already in the Widget tree

環境

  • Flutterバージョン: 3.3.8
  • google_mobile_ads: 2.2.0

原因

エラーの通りではありますが、同一のAdWidgetが生成されている事が原因でした。
AdWidgetの引数にBannerAdクラスのインスタンスを渡すようになっていますが、この引数に指定したインスタンスが同一の場合に、同一のAdWidgetとして認識されるようです。

  • エラーコード
  
  Widget build(BuildContext context, WidgetRef ref) {
        final myBanner = ref.watch(admobBannerProvider)...省略
	
          SizedBox(
            height: 50.0,
            child: AdWidget(ad: myBanner),  // myBannerの部分が同一のインスタンスのためエラーになっていた
          ),
	
	...
    }
  • provider定義
final admobBannerProvider = Provider<BannerAd>((ref) {
  return BannerAd(
    adUnitId: <広告ユニットID>,
    size: AdSize.banner,
    request: const AdRequest(),
    listener: const BannerAdListener()
  )..load();
});

余談ですが、google_mobile_adsの旧バージョンでは同一のAdWidgetを複数箇所で使用できたみたいです。ただ、自分が使用したv2.2.0ではそのような仕様変更が入ったようでした。

解決策

バナー設置箇所(AdWidget)ごとに新しいBannerAdクラスのインスタンスを生成してあげる。

  1. BannerAdクラスのインスタンスを生成しやすいように汎用クラスを作成。
class AdmobManager {
  BannerAd get bannerAd {
    return BannerAd(
      adUnitId: <広告ユニットID>, // 環境ごとに取得する
      size: AdSize.banner,
      request: const AdRequest(),
      listener: const BannerAdListener(),
    )..load();
  }
}
  1. View側でAdWidget使用箇所ごとに都度、別のインスタンスを生成して渡す。
  
  Widget build(BuildContext context, WidgetRef ref) {
	
	...省略
	
          SizedBox(
            height: 50.0,
            child: AdWidget(ad: AdmobManager().bannerAd),  // AdmobManager().bannerAd:新しいインスタンスを生成
          ),
	
	...
    }

無事、広告を表示することが出来ました。

最後に

2022/12/22追記

Discussion