Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

getCurrentOrientationInlineAdaptiveBannerAdSize does not load inline ads #888

Open
lukeirvin opened this issue Jul 19, 2023 · 9 comments
Open
Assignees
Labels
banner ad Issues related to Banner Ad bug Something isn't working e2-days Effort: < 5 days p2-medium

Comments

@lukeirvin
Copy link

lukeirvin commented Jul 19, 2023

flutter version - 3.7.12
dart version - 2.19.6
xcode version - 14.3.1
google_mobile_ads version - 2.4.0

I'm trying to create inline adaptive ads to display in a list view, but when trying to set the size using getCurrentOrientationInlineAdaptiveBannerAdSize, the ads will fail.

I am using the inline example provided here, but changed it slightly:

import 'package:flutter/material.dart';
import 'package:google_mobile_ads/google_mobile_ads.dart';

class InlineAdaptiveExample extends StatefulWidget {
  @override
  _InlineAdaptiveExampleState createState() => _InlineAdaptiveExampleState();
}

class _InlineAdaptiveExampleState extends State<InlineAdaptiveExample> {
 
  AdManagerBannerAd? _inlineAdaptiveAd;
  bool _isLoaded = false;
  AdSize? _adSize;
  late Orientation _currentOrientation;

  double get _adWidth => MediaQuery.of(context).size.width;

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    _currentOrientation = MediaQuery.of(context).orientation;
    _loadAd();
  }

  void _loadAd() async {
    await _inlineAdaptiveAd?.dispose();
    setState(() {
      _inlineAdaptiveAd = null;
      _isLoaded = false;
    });

    AdSize size = AdSize.getCurrentOrientationInlineAdaptiveBannerAdSize(
        _adWidth.truncate());

    _inlineAdaptiveAd = AdManagerBannerAd(
      // TODO: replace with your own ad unit.
      adUnitId: '<your-ad-unit>',
      sizes: [size],
      request: AdManagerAdRequest(),
      listener: AdManagerBannerAdListener(
        onAdLoaded: (Ad ad) async {

          AdManagerBannerAd bannerAd = (ad as AdManagerBannerAd);
          final AdSize? size = await bannerAd.getPlatformAdSize();
          if (size == null) {
            print('Error: getPlatformAdSize() returned null for $bannerAd');
            return;
          }

          setState(() {
            _inlineAdaptiveAd = bannerAd;
            _isLoaded = true;
            _adSize = size;
          });
        },
        onAdFailedToLoad: (Ad ad, LoadAdError error) {
          ad.dispose();
        },
      ),
    )..load();
  }

  @override
  Widget build(BuildContext context) {
    return _isLoaded
        ? StatefulBuilder(
            builder: (context, setState) => _buildContentFeedAdUI(),
          )
        : const SizedBox.shrink();
  }

  _buildContentFeedAdUI() {
    return Align(
            alignment: Alignment.center,
            child: SafeArea(
              child: SizedBox(
                width: _adWidth,
                height: _adSize!.height.toDouble(),
                child: AdWidget(ad: _inlineAdaptiveAd!),
              ),
            ),
          );
  }

  @override
  void dispose() {
    super.dispose();
    _inlineAdaptiveAd?.dispose();
  }
}

If I replace size with either AdSize.banner or AdSize.mediumRectangle, then the ad loads fine, otherwise I just get an empty space where the ad should be.

The error I am getting is:

AdManagerBannerAd failed to load: LoadAdError(code: 1, domain: com.google.admob, message: Request Error: No ad to show., responseInfo: ResponseInfo(responseId: null, mediationAdapterClassName: null, adapterResponses: [], loadedAdapterResponseInfo: AdapterResponseInfo(adapterClassName: , latencyMillis: 0, description: , adUnitMapping: {}, adError: null, adSourceName: , adSourceId: , adSourceInstanceName: , adSourceInstanceId: )), responseExtras: {})

@huycozy huycozy added the in triage Issue currently being evaluated label Jul 20, 2023
@huycozy
Copy link
Collaborator

huycozy commented Jul 20, 2023

Hi @lukeirvin
Can you try changing the ad unit to /6499/example/banner to see if it works??

@huycozy huycozy added the feedback required Further information is requested label Jul 20, 2023
@lukeirvin
Copy link
Author

lukeirvin commented Jul 20, 2023

Hi @lukeirvin Can you try changing the ad unit to /6499/example/banner to see if it works??

Hi @huycozy

Thank you so much for your reply. Yes, I have tried this multiple times before, and trying again now. I still get an error when trying to display inline adaptive ads. Same error as what I shared above. The online time I can get this to go away is if I either hardcode a height/width value OR if I set the size to be something like AdSize.mediumRectangle vs. calculating the width & height.

Update:
I also notice that right when I start up my app, I see in my console that an ad is loaded & I see returned size values. The first ad is the first cell that is off-screen, or not visible. Once I scroll my listview up to bring it to be visible, I get the error that it can't load. Happens with every adaptive ad in the feed. I can see the box with the size where it should be, but nothing loads there.

I have banner ads as well & those load without any issues.

Update 2:
Looking at the size values as things load:

From AdSize size = AdSize.getCurrentOrientationInlineAdaptiveBannerAdSize( _adWidth.truncate());:
height: 0
width: 393

Then within onAdLoaded:
height: 100
width: 393

Then within my method of returning the AdWidget:
my _adSize.height is 100
but, the _bannerAd!.sizes.first.height is 0

Is it possible it is failing because the _bannerAd!.sizes.first.height is 0?

@github-actions github-actions bot removed the feedback required Further information is requested label Jul 20, 2023
@huycozy
Copy link
Collaborator

huycozy commented Jul 21, 2023

_bannerAd!.sizes.first.height is 0

I see this now. But even so, the ad still displays. Does it display on your device?

Also, looks like sizes is only available in a specific case, see:

/// Ad sizes supported by this [AdManagerBannerAd].
///
/// In most cases, only one ad size will be specified. Multiple ad sizes can
/// be specified if your application can appropriately handle multiple ad
/// sizes. If multiple ad sizes are specified, the [AdManagerBannerAd] will
/// assume the size of the first ad size until an ad is loaded.
final List<AdSize> sizes;

@huycozy huycozy added the feedback required Further information is requested label Jul 21, 2023
@lukeirvin
Copy link
Author

@huycozy

Correct, I need to make inline adaptive ads & per the documentation, I would need to use sizes

No, the ad does NOT display for me. Just an empty space.

@github-actions github-actions bot removed the feedback required Further information is requested label Jul 21, 2023
@huycozy
Copy link
Collaborator

huycozy commented Jul 24, 2023

No, the ad does NOT display for me. Just an empty space.

Strange, I always see the ads. bannerAd.sizes's ad height is 0, though.

Demo

I see you are using an old plugin version google_mobile_ads version - 2.4.0. Can you try upgrading to the latest version google_mobile_ads: ^3.0.0 and observe if the ad can be displayed? Or you can check this on plugin sample code.

@huycozy huycozy added the feedback required Further information is requested label Jul 24, 2023
@lukeirvin
Copy link
Author

@huycozy

I'll try to update the plugin. I know it will fail initially as I'll have to update some of the other packages as well to support it.

I have followed the example code exactly as it is & it never works for me.

Also to note, the only difference between the example & what I am doing is the example shows the ad at one index location. I'll need to show it at multiple indexes within a ListView.

@github-actions github-actions bot removed the feedback required Further information is requested label Jul 24, 2023
@huycozy
Copy link
Collaborator

huycozy commented Jul 25, 2023

Thanks for your response. The context is more clear now. It seems there is an issue with the AdWidget loading mechanism in your ListView. In ListView, you should create isolated AdWidget instances (to ignore the error This AdWidget is already in the Widget tree). Can you please share a minimal sample code for this case?

@huycozy huycozy added the feedback required Further information is requested label Jul 25, 2023
@lukeirvin
Copy link
Author

@huycozy

I hope this is enough.

I have a dart file where I create my Inline Ad, as I have many files where I will want to show ads. I'm doing custom targeting as well so I pass those in as params.

Then I gave a rough example setup of one of my feeds.

There's quite a bit going on with my Pages/UI so I had to strip a lot of that away, but many of my pages may have additional custom cells & then at certain indexes, I want to show ads.

To note, I did test this by bringing all of the ad logic into the file that has one of my feeds to see if that helped but I would get the same results. Ideally trying to keep from having to repeat the logic.

import 'package:flutter/material.dart';
import 'package:google_mobile_ads/google_mobile_ads.dart';

class MyInlineCell extends StatefulWidget {
  final String tag;
  final String param1;
  final String param2;

  const MyInlineCell({
    Key? key,
    required this.tag,
    required this.param1,
    required this.param2,
  }) : super(
          key: key,
        );

  @override
  _MyInlineCellState createState() => _MyInlineCellState();
}

class _MyInlineCellState extends State<MyInlineCell> {
  AdManagerBannerAd? _inlineAdaptiveAd;
  bool _isLoaded = false;
  AdSize? _adSize;

  @override
  void initState() {
    super.initState();
    _loadAd();
  }

  void _loadAd() async {
    AdSize size = AdSize.getCurrentOrientationInlineAdaptiveBannerAdSize(
        _adWidth.truncate());

    _inlineAdaptiveAd = AdManagerBannerAd(
      adUnitId: widget.tag,
      sizes: [size],
      request: AdManagerAdRequest(
        customTargeting: {
          'param1': widget.param1,
          'param2': widget.param2,
        },
      ),
      listener: AdManagerBannerAdListener(
        onAdLoaded: (Ad ad) async {
          AdManagerBannerAd bannerAd = (ad as AdManagerBannerAd);
          final AdSize? size = await bannerAd.getPlatformAdSize();
          if (size == null) {
             return;
          }

          setState(() {
            _inlineAdaptiveAd = bannerAd;
            _isLoaded = true;
            _adSize = size;
          });
        },
        onAdFailedToLoad: (Ad ad, LoadAdError error) {
          ad.dispose();
        },
      ),
    )..load();
  }

  Widget _getAdWidget() {
    return Align(
      alignment: Alignment.center,
      child: SafeArea(
        child: SizedBox(
          width: _adWidth,
          height: _adSize!.height.toDouble(),
          child: AdWidget(ad: _inlineAdaptiveAd!),
        ),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return _isLoaded
        ? StatefulBuilder(
            builder: (context, setState) => _getAdWidget(),
          )
        : const SizedBox.shrink();
  }

  @override
  void dispose() {
    super.dispose();
    _inlineAdaptiveAd?.dispose();
  }
}

import 'package:flutter/material.dart';
import '../myInlineCell.dart';

class MyFeedPage extends StatefulWidget {
  const MyFeedPage({Key? key}) : super(key: key);

  @override
  _MyFeedPageState createState() => _MyFeedPageState();
}

class _MyFeedPageState extends State<MyFeedPage> {

    @override
    Widget build(BuildContext context) {
        return _buildListView();
    }

    _buildListView() {
        return SmartRefresher(
              controller: _refreshController,
              onRefresh: _onRefresh,
              child: ListView.separated(
                shrinkWrap: true,
                controller: _scrollController,
                physics: BouncingScrollPhysics(),
                padding: const EdgeInsets.only(bottom: 70.0),
                separatorBuilder: (BuildContext context, int index) {
                  return (index > 0)
                      ? Divider(
                          height: 1,
                          color: Colors.black,
                        )
                      : Divider(
                          height: 0,
                        );
                },
                itemBuilder: (context, index) {
                
                  if (index == 0) {
                    return CustomCellOne();
                  }

                  if (index == 1) {
                    return CustomCellTwo();
                  }

                  // Inline Banner
                  if (index % 3 == 0) {
                    if (_needToShowAd) {
                      return Column(
                        children: [
                          MyInlineCell(
                            tag: 'ad unit id',
                            param1: 'abc',
                            param2: '123',
                          ),
                          MyListItemCell()
                        ],
                      );
                    }
                  }

                  return MyListItemCell();
                },
                itemCount: 100, // this value is just an example.
              ),
            ),
          ),
        ],
      ),
    );
    }
}

@github-actions github-actions bot removed the feedback required Further information is requested label Jul 25, 2023
@huycozy
Copy link
Collaborator

huycozy commented Jul 26, 2023

Thanks for your response and patience. The example above is incomplete and not minimal (using 3rd package, undefined widgets), so I borrow the sample code of OP at #892 and modified it as below.

And I confirm I can see the issue now with sizes from getCurrentOrientationInlineAdaptiveBannerAdSize, it returns height as 0 (corresponding to empty space in demo video below). Using getPlatformAdSize is a workaround (as I used it in sample code below in commented code).

Meanwhile, other AdSize (such as AdSize.banner, AdSize.mediumRectangle, AdSize.largeBanner) return correct non-zero height as expected.

Demo
Screen.Recording.2023-07-26.at.19.06.56.mov
Complete sample code
import 'package:flutter/material.dart';
import 'package:google_mobile_ads/google_mobile_ads.dart';

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  MobileAds.instance
    ..initialize()
    ..updateRequestConfiguration(RequestConfiguration(
      testDeviceIds: <String>['20FB23B5E117EC42488FBC0A024F306F'],
    ));
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'ONE DEMO GOOGLE ADS APP'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  AdManagerBannerAd? underMainArticleBanner;
  AdManagerBannerAd? aboveVideoSectionBanner;
  AdManagerBannerAd? underVideoSectionBanner;
  AdManagerBannerAd? underGlitchesSectionBanner;

  static const _insets = 16.0;

  double get _adWidth => MediaQuery.of(context).size.width - (2 * _insets);
  late AdSize size;
  AdSize? _adPlatformSize;

  Future createUnderGlitchesBannerAd() async {
    await AdManagerBannerAd(
      adUnitId: '/6499/example/banner',
      sizes: [size],
      request: const AdManagerAdRequest(),
      listener: AdManagerBannerAdListener(
        onAdLoaded: (ad) {
          setState(() {
            underGlitchesSectionBanner = ad as AdManagerBannerAd;
            setState(() async {
              _adPlatformSize = await underGlitchesSectionBanner!.getPlatformAdSize();
            });
          });
        },
        onAdFailedToLoad: (ad, error) {
          setState(() {
            underGlitchesSectionBanner = null;
          });
          print('Ad load failed (code=${error.code} message=${error.message})');
          ad.dispose();
        },
      ),
    ).load();
  }

  Future createAboveVideoSectionBannerAd() async {
    await AdManagerBannerAd(
      adUnitId: '/6499/example/banner',
      sizes: [AdSize.banner],
      request: const AdManagerAdRequest(),
      listener: AdManagerBannerAdListener(
        onAdLoaded: (ad) {
          setState(() {
            aboveVideoSectionBanner = ad as AdManagerBannerAd;
          });
        },
        onAdFailedToLoad: (ad, error) {
          setState(() {
            aboveVideoSectionBanner = null;
          });
          print('Ad load failed (code=${error.code} message=${error.message})');
          ad.dispose();
        },
      ),
    ).load();
  }

  Future createUnderVideoSectionBannerAd() async {
    await AdManagerBannerAd(
      adUnitId: '/6499/example/banner',
      sizes: [AdSize.largeBanner],
      request: const AdManagerAdRequest(),
      listener: AdManagerBannerAdListener(
        onAdLoaded: (ad) {
          setState(() {
            underVideoSectionBanner = ad as AdManagerBannerAd;
          });
        },
        onAdFailedToLoad: (ad, error) {
          setState(() {
            underVideoSectionBanner = null;
          });
          print('Ad load failed (code=${error.code} message=${error.message})');
          ad.dispose();
        },
      ),
    ).load();
  }

  Future createUnderMainArticleBannerAd() async {
    await AdManagerBannerAd(
      adUnitId: '/6499/example/banner',
      sizes: [AdSize.mediumRectangle],
      request: const AdManagerAdRequest(),
      listener: AdManagerBannerAdListener(
        onAdLoaded: (ad) {
          setState(() {
            underMainArticleBanner = ad as AdManagerBannerAd;
          });
        },
        onAdFailedToLoad: (ad, error) {
          setState(() {
            underMainArticleBanner = null;
          });
          print('Ad load failed (code=${error.code} message=${error.message})');
          ad.dispose();
        },
      ),
    ).load();
  }

  @override
  void initState() {
    super.initState();
  }

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    size = AdSize.getCurrentOrientationInlineAdaptiveBannerAdSize(_adWidth.truncate());

    createUnderMainArticleBannerAd();
    createAboveVideoSectionBannerAd();
    createUnderGlitchesBannerAd();
    createUnderVideoSectionBannerAd();
  }

  @override
  Widget build(BuildContext context) {

    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: ListView(
        children: [
          Container(
            height: 100,
            color: Colors.blue,
            alignment: Alignment.center,
            child: Text('InlineAdaptiveBannerAdSize'),
          ),
          underGlitchesSectionBanner != null
              ? Container(
                  color: const Color(0xFFD0D0D0),
                  // height: _adPlatformSize?.height.toDouble() ?? 0,
                  height: underGlitchesSectionBanner!.sizes[0].height.toDouble(),
                  width: MediaQuery.of(context).size.width,
                  child: AdWidget(ad: underGlitchesSectionBanner!),
                )
              : const SizedBox.shrink(),
          Container(
            height: 100,
            color: Colors.blue,
            alignment: Alignment.center,
            child: Text('AdSize.mediumRectangle'),
          ),
          underMainArticleBanner != null
              ? Container(
                  color: const Color(0xFFD0D0D0),
                  height: underMainArticleBanner!.sizes[0].height.toDouble(),
                  width: MediaQuery.of(context).size.width,
                  child: AdWidget(ad: underMainArticleBanner!),
                )
              : const SizedBox.shrink(),
          Container(
            height: 100,
            color: Colors.blue,
            alignment: Alignment.center,
            child: Text('AdSize.banner'),
          ),
          aboveVideoSectionBanner != null
              ? Container(
                  color: const Color(0xFFD0D0D0),
                  height: aboveVideoSectionBanner!.sizes[0].height.toDouble(),
                  width: MediaQuery.of(context).size.width,
                  child: AdWidget(ad: aboveVideoSectionBanner!),
                )
              : const SizedBox.shrink(),
          Container(
            height: 100,
            color: Colors.blue,
            alignment: Alignment.center,
            child: Text('AdSize.largeBanner'),
          ),
          underVideoSectionBanner != null
              ? Container(
                  color: const Color(0xFFD0D0D0),
                  height: underVideoSectionBanner!.sizes[0].height.toDouble(),
                  width: MediaQuery.of(context).size.width,
                  child: AdWidget(ad: underVideoSectionBanner!),
                )
              : const SizedBox.shrink(),
        ],
      ),
    );
  }
}

Reproduced the issue on the latest plugin version: google_mobile_ads: ^3.0.0.

@huycozy huycozy added bug Something isn't working p2-medium e2-days Effort: < 5 days banner ad Issues related to Banner Ad and removed in triage Issue currently being evaluated labels Jul 26, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
banner ad Issues related to Banner Ad bug Something isn't working e2-days Effort: < 5 days p2-medium
Projects
None yet
Development

No branches or pull requests

3 participants