7

Flutter Sdk: 3.27.1 google_mobile_ads: ^6.0.0

0

I am facing this issue on Samsung F23, Android 14, API 34 when the app starts I display the Ad on the Home Screen and that is working well but when I navigate to the other page where I place the Ad that one is making problems Sometimes it shows, and sometimes it does not.

However, the Ad is clickable, so each time I tap on the white space, it opens the advertiser's link.

Here you can see the Screen Shots

===> where show ads ===> where ads not in screen but clickable!

package xxx.xxx.app import android.view.LayoutInflater import android.view.View import android.widget.Button import android.widget.ImageView import android.widget.RatingBar import android.widget.TextView import com.google.android.gms.ads.nativead.NativeAd import com.google.android.gms.ads.nativead.NativeAdView import io.flutter.embedding.android.FlutterActivity import io.flutter.embedding.engine.FlutterEngine import io.flutter.plugins.googlemobileads.GoogleMobileAdsPlugin import io.flutter.plugins.googlemobileads.GoogleMobileAdsPlugin.NativeAdFactory import androidx.browser.customtabs.CustomTabsIntent import android.content.ActivityNotFoundException import android.net.Uri import android.widget.Toast import io.flutter.plugin.common.MethodChannel class MainActivity: FlutterActivity() { private val CHANNEL = "browser_launcher" private var browserLaunched = false override fun configureFlutterEngine(flutterEngine: FlutterEngine) { flutterEngine.plugins.add(GoogleMobileAdsPlugin()) super.configureFlutterEngine(flutterEngine) // Register native ad factories GoogleMobileAdsPlugin.registerNativeAdFactory( flutterEngine, "NativeMedium", MediumNativeAdFactory(layoutInflater)) GoogleMobileAdsPlugin.registerNativeAdFactory( flutterEngine, "NativeSmall", SmallNativeAdFactory(layoutInflater)) // Set up method channel for custom tabs MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result -> when (call.method) { "launchCustomTabs" -> { val url = call.argument<String>("url") if (url != null) { try { val customTabsIntent = CustomTabsIntent.Builder().build() customTabsIntent.intent.data = Uri.parse(url) browserLaunched = true // Notify Flutter before launching browser MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL) .invokeMethod("onBrowserLaunching", null) startActivity(customTabsIntent.intent) result.success(null) } catch (e: ActivityNotFoundException) { Toast.makeText( this, "No browser found to open the URL", Toast.LENGTH_LONG ).show() result.error("BROWSER_NOT_FOUND", "No browser found to open the URL", null) } } else { result.error("INVALID_URL", "URL cannot be null", null) } } else -> { result.notImplemented() } } } } override fun cleanUpFlutterEngine(flutterEngine: FlutterEngine) { GoogleMobileAdsPlugin.unregisterNativeAdFactory(flutterEngine, "NativeMedium") GoogleMobileAdsPlugin.unregisterNativeAdFactory(flutterEngine, "NativeSmall") } override fun onResume() { super.onResume() if (browserLaunched) { browserLaunched = false // Notify Flutter that we're back from the browser flutterEngine?.dartExecutor?.binaryMessenger?.let { messenger -> MethodChannel(messenger, CHANNEL).invokeMethod("onBrowserClosed", null) } } } } class MediumNativeAdFactory: NativeAdFactory { private var layoutInflater: LayoutInflater constructor(layoutInflater: LayoutInflater) { this.layoutInflater = layoutInflater } override fun createNativeAd(nativeAd: NativeAd?, customOptions: MutableMap<String, Any>?): NativeAdView { val adView = layoutInflater.inflate(R.layout.my_native_ad, null) as NativeAdView // Set the media view. adView.mediaView = adView.findViewById(R.id.ad_media) // Hide MediaView if no mediaContent to avoid blank space if (nativeAd?.mediaContent == null) { adView.mediaView?.visibility = View.GONE } else { adView.mediaView?.visibility = View.VISIBLE } // Set other ad assets. adView.headlineView = adView.findViewById(R.id.ad_headline) adView.bodyView = adView.findViewById(R.id.ad_body) adView.callToActionView = adView.findViewById(R.id.ad_call_to_action) adView.iconView = adView.findViewById(R.id.ad_app_icon) adView.starRatingView = adView.findViewById(R.id.ad_stars) val advertiserView: TextView? = adView.findViewById(R.id.ad_advertiser) // The headline is guaranteed to be in every NativeAd. (adView.headlineView as TextView).text = nativeAd?.headline adView.mediaView?.mediaContent = nativeAd?.mediaContent // These assets aren't guaranteed to be in every NativeAd, so it's important to // check before trying to display them. if (nativeAd?.body == null) { adView.bodyView?.visibility = View.INVISIBLE } else { adView.bodyView?.visibility = View.VISIBLE (adView.bodyView as TextView).text = nativeAd.body } if (advertiserView != null) { val advertiser = nativeAd?.advertiser if (advertiser.isNullOrBlank()) { advertiserView.visibility = View.GONE } else { advertiserView.text = advertiser advertiserView.visibility = View.VISIBLE } } if (nativeAd?.callToAction == null) { adView.callToActionView?.visibility = View.INVISIBLE } else { adView.callToActionView?.visibility = View.VISIBLE (adView.callToActionView as Button).text = nativeAd.callToAction } if (nativeAd?.icon == null) { adView.iconView?.visibility = View.GONE } else { (adView.iconView as ImageView).setImageDrawable(nativeAd.icon!!.drawable) adView.iconView?.visibility = View.VISIBLE } if (nativeAd?.starRating == null) { adView.starRatingView?.visibility = View.GONE } else { (adView.starRatingView as RatingBar).rating = nativeAd.starRating!!.toFloat() adView.starRatingView?.visibility = View.VISIBLE } // Advertiser already bound above using advertiserView // This method tells the Google Mobile Ads SDK that you have finished populating your // native ad view with this native ad. if (nativeAd != null) { adView.setNativeAd(nativeAd) } return adView } } class SmallNativeAdFactory: NativeAdFactory { private var layoutInflater: LayoutInflater constructor(layoutInflater: LayoutInflater) { this.layoutInflater = layoutInflater } override fun createNativeAd(nativeAd: NativeAd?, customOptions: MutableMap<String, Any>?): NativeAdView { val adView = layoutInflater.inflate(R.layout.native_small, null) as NativeAdView // Set other ad assets. adView.headlineView = adView.findViewById(R.id.ad_headline) adView.bodyView = adView.findViewById(R.id.ad_body) adView.callToActionView = adView.findViewById(R.id.ad_call_to_action) adView.iconView = adView.findViewById(R.id.ad_app_icon) adView.starRatingView = adView.findViewById(R.id.ad_stars) val advertiserView: TextView? = adView.findViewById(R.id.ad_advertiser) // The headline is guaranteed to be in every NativeAd. (adView.headlineView as TextView).text = nativeAd?.headline // These assets aren't guaranteed to be in every NativeAd, so it's important to // check before trying to display them. if (nativeAd?.body.isNullOrBlank()) { adView.bodyView?.visibility = View.GONE } else { adView.bodyView?.visibility = View.VISIBLE (adView.bodyView as TextView).text = nativeAd.body } // Advertiser is already handled above if (nativeAd?.callToAction.isNullOrBlank()) { adView.callToActionView?.visibility = View.GONE } else { adView.callToActionView?.visibility = View.VISIBLE (adView.callToActionView as Button).text = nativeAd.callToAction } if (nativeAd?.icon == null) { adView.iconView?.visibility = View.GONE } else { (adView.iconView as ImageView).setImageDrawable(nativeAd.icon!!.drawable) adView.iconView?.visibility = View.VISIBLE } if (nativeAd?.starRating == null) { adView.starRatingView?.visibility = View.GONE } else { (adView.starRatingView as RatingBar).rating = nativeAd.starRating!!.toFloat() adView.starRatingView?.visibility = View.VISIBLE } if (advertiserView != null) { val advertiser = nativeAd?.advertiser if (advertiser.isNullOrBlank()) { advertiserView.visibility = View.GONE } else { advertiserView.text = advertiser advertiserView.visibility = View.VISIBLE } } // This method tells the Google Mobile Ads SDK that you have finished populating your // native ad view with this native ad. if (nativeAd != null) { adView.setNativeAd(nativeAd) } return adView } } 
///load native ad Future<void> loadGoogleBannerAds(String adGoogleUnitId) async { await _googleNativeAd?.dispose(); _googleNativeAd = NativeAd( adUnitId: adGoogleUnitId, request: const AdRequest(), factoryId: 'NativeSmall', listener: NativeAdListener( onAdLoaded: (ad) { print('AD onAdLoaded'); if (mounted) { setState(() { _googleNativeAd = ad as NativeAd; valueSet.value = BannerShimmerValue.success; }); } else { ad.dispose(); } }, onAdFailedToLoad: (ad, err) { print('AD onAdFailedToLoad'); ad.dispose(); if (mounted) { setState(() { _googleNativeAd = null; }); } loadGoogleBannerFailedAds(); }, onAdOpened: (Ad ad) {}, onAdClosed: (Ad ad) {}, onAdImpression: (Ad ad) { print('AD Impression'); }, ), )..load(); } ///show native ad if (_googleNativeAd != null) { print('_googleNativeAd != null'); return SizedBox( height: 100, width: MediaQuery.of(context).size.width, // full width child: AdWidget(key: ValueKey(_googleNativeAd), ad: _googleNativeAd!), ); } 

1 Answer 1

-1

Try doing like this.

import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:google_mobile_ads/google_mobile_ads.dart'; class AdExampleScreen extends StatefulWidget { @override _AdExampleScreenState createState() => _AdExampleScreenState(); } class _AdExampleScreenState extends State<AdExampleScreen> { NativeAd? _mediumAd; NativeAd? _smallAd; bool _mediumAdIsLoaded = false; bool _smallAdIsLoaded = false; // MethodChannel for your Custom Tabs (for non-ad links) static const platform = MethodChannel('browser_launcher'); @override void initState() { super.initState(); // Initialize Google Mobile Ads SDK MobileAds.instance.initialize(); // Optional: Configure test devices for debugging MobileAds.instance.updateRequestConfiguration( RequestConfiguration( testDeviceIds: ['YOUR_EMULATOR_OR_DEVICE_ID'], // Get from logs: 'To get test ads on this device...' ), ); // Load ads on init _loadMediumAd(); _loadSmallAd(); } // Load Medium Native Ad void _loadMediumAd() { _mediumAd?.dispose(); _mediumAd = NativeAd( adUnitId: 'ca-app-pub-3940256099942544/2247696110', // Test ID; replace with yours factoryId: 'NativeMedium', // Matches your factory in MainActivity listener: NativeAdListener( onAdLoaded: (ad) { print('Medium NativeAd loaded.'); setState(() { _mediumAdIsLoaded = true; }); }, onAdFailedToLoad: (ad, error) { print('Medium NativeAd failed to load: ${error.errorCode}: ${error.message}'); ad.dispose(); setState(() { _mediumAdIsLoaded = false; }); }, onAdClicked: (ad) { print('Medium NativeAd clicked! (SDK handles opening URL)'); // Optional: Track custom analytics here // Note: Do NOT override the click action; let SDK open the browser }, onAdImpression: (ad) { print('Medium NativeAd impression recorded.'); }, ), nativeAdOptions: const NativeAdOptions( videoOptions: VideoOptions( mute: true, // Mute videos by default ), // clickUrl: 'https://your-click-tracking.com', // Optional for additional tracking ), ); _mediumAd!.load(); } // Load Small Native Ad void _loadSmallAd() { _smallAd?.dispose(); _smallAd = NativeAd( adUnitId: 'ca-app-pub-3940256099942544/2652932962', // Test ID; replace with yours factoryId: 'NativeSmall', // Matches your factory in MainActivity listener: NativeAdListener( onAdLoaded: (ad) { print('Small NativeAd loaded.'); setState(() { _smallAdIsLoaded = true; }); }, onAdFailedToLoad: (ad, error) { print('Small NativeAd failed to load: ${error.errorCode}: ${error.message}'); ad.dispose(); setState(() { _smallAdIsLoaded = false; }); }, onAdClicked: (ad) { print('Small NativeAd clicked! (SDK handles opening URL)'); // Optional: Track custom analytics here }, onAdImpression: (ad) { print('Small NativeAd impression recorded.'); }, ), nativeAdOptions: const NativeAdOptions( videoOptions: VideoOptions( mute: true, ), ), ); _smallAd!.load(); } // Reload both ads (for testing) void _reloadAds() { _loadMediumAd(); _loadSmallAd(); } // Example: Launch Custom Tabs for a non-ad URL (using your channel) Future<void> _launchCustomTabs(String url) async { try { await platform.invokeMethod('launchCustomTabs', {'url': url}); } on PlatformException catch (e) { print('Failed to launch Custom Tabs: ${e.message}'); // Fallback: Use url_launcher or show error } } @override void dispose() { _mediumAd?.dispose(); _smallAd?.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Native Ads Example'), actions: [ IconButton( icon: const Icon(Icons.refresh), onPressed: _reloadAds, tooltip: 'Reload Ads', ), ], ), body: SingleChildScrollView( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ // Medium Ad Section Card( elevation: 4, child: Padding( padding: const EdgeInsets.all(8.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( 'Medium Native Ad', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), ), const SizedBox(height: 8), if (_mediumAdIsLoaded) SizedBox( width: double.infinity, height: 200, // Adjust based on your layout (media + text) child: AdWidget(ad: _mediumAd!), ) else const Center( child: Padding( padding: EdgeInsets.all(16.0), child: CircularProgressIndicator(), ), ), if (!_mediumAdIsLoaded) const Text( 'Loading Medium Ad...', style: TextStyle(color: Colors.grey), ), ], ), ), ), const SizedBox(height: 20), // Small Ad Section Card( elevation: 4, child: Padding( padding: const EdgeInsets.all(8.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( 'Small Native Ad', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), ), const SizedBox(height: 8), if (_smallAdIsLoaded) SizedBox( width: double.infinity, height: 120, // Adjust for small layout (no media) child: AdWidget(ad: _smallAd!), ) else const Center( child: Padding( padding: EdgeInsets.all(16.0), child: CircularProgressIndicator(), ), ), if (!_smallAdIsLoaded) const Text( 'Loading Small Ad...', style: TextStyle(color: Colors.grey), ), ], ), ), ), const SizedBox(height: 20), // Example: Non-Ad Button Using Custom Tabs ElevatedButton( onPressed: () => _launchCustomTabs('https://flutter.dev'), // Test URL child: const Text('Open Flutter.dev in Custom Tabs (Non-Ad)'), ), const SizedBox(height: 10), const Text( 'Notes:\n' '- Tap ad elements (headline, CTA, icon) to test clicks.\n' '- Ads open in default browser (SDK handles).\n' '- Check console for load/click logs.\n' '- Use test IDs; switch to real for production.', style: TextStyle(fontSize: 12, color: Colors.grey), ), ], ), ), ); } } 
Sign up to request clarification or add additional context in comments.

1 Comment

How does this address the issue? Please edit your answer and explain the changes you've made to solve the problem.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.