🚨

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

2022/11/15に公開約1,900字

現象

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:新しいインスタンスを生成
          ),
	
	...
    }

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

最後に

画面を跨いで広告を表示する場合にも、今回のようなエラーが発生していたので同様に対応しました。
ただ、今回のようにListViewで無限に呼ばれる可能性があるのでパフォーマンス的に怪しいかなと懸念しています。
もし、もっと良い解決策をご存知の方いれば是非教えてください。

Discussion

ログインするとコメントできます