On this page13 sections
  1. Prerequisites
  2. Connection With Previous Lectures
  3. Learning Objectives
  4. Lesson
  5. 1. The Helper
  6. 2. The Screen
  7. Code Examples
  8. Common Beginner Mistakes
  9. Best Practices
  10. Mini Challenge
  11. Practice Questions
  12. Practice Answers
  13. Key Takeaways

Lecture 007 — Native Ads

Category3 — Native & Rewarded Ads
Lecture007 of 010
Estimated video length18 min
TargetFlutter 3.44 · Dart 3.12 · google_mobile_ads 9
LevelBeginner
Source codeGitHub — urraan_admob_final

A native ad takes the shape of your own screen. With a template style you set colours and fonts from Dart and Google fills in the rest — no platform code.

Contents

Prerequisites · Connection · Objectives · Lesson · Code Examples · Common Mistakes · Best Practices · Mini Challenge · Practice Questions · Answers · Takeaways


Prerequisites

Lectures 001–004.


Connection With Previous Lectures

Banner ads are a plain strip. Native ads fit into content, which usually earns more clicks and annoys less.


Learning Objectives

By the end of this lecture you will be able to:

  • Create a NativeAd with a NativeTemplateStyle
  • Choose small or medium templates
  • Show it with AdWidget in a fixed-height box
  • Dispose it with the screen

Lesson

1. The Helper

dart
// lib/admob/native_ad_helper.dart
import 'package:flutter/material.dart';
import 'package:google_mobile_ads/google_mobile_ads.dart';

import 'admob_manager.dart';

class NativeAdHelper {
  NativeAd? _nativeAd;
  bool isLoaded = false;

  void loadNativeAd(
    VoidCallback onAdLoaded, {
    TemplateType type = TemplateType.small,
  }) {
    _nativeAd?.dispose();
    isLoaded = false;
    _nativeAd = NativeAd(
      adUnitId: AdmobManager.nativeId,
      listener: NativeAdListener(
        onAdLoaded: (_) {
          isLoaded = true;
          onAdLoaded();
        },
        onAdFailedToLoad: (ad, error) {
          debugPrint('Native failed: ${error.code} ${error.message}');
          ad.dispose();
        },
      ),
      request: const AdRequest(),
      nativeTemplateStyle: NativeTemplateStyle(
        templateType: type,
        mainBackgroundColor: const Color(0xfffffbed),
        callToActionTextStyle: NativeTemplateTextStyle(
          textColor: Colors.white,
          style: NativeTemplateFontStyle.monospace,
          size: 16,
        ),
        primaryTextStyle: NativeTemplateTextStyle(
          textColor: Colors.black,
          style: NativeTemplateFontStyle.bold,
          size: 16,
        ),
        secondaryTextStyle: NativeTemplateTextStyle(
          textColor: Colors.black,
          style: NativeTemplateFontStyle.italic,
          size: 16,
        ),
        tertiaryTextStyle: NativeTemplateTextStyle(
          textColor: Colors.black,
          style: NativeTemplateFontStyle.normal,
          size: 16,
        ),
      ),
    )..load();
  }

  NativeAd? get nativeAd => isLoaded ? _nativeAd : null;

  void dispose() => _nativeAd?.dispose();

  static Widget getNativeAdView({
    required bool isPurchase,
    required bool isLoaded,
    required NativeAd? nativeAd,
    double height = 100,
  }) {
    if (isPurchase || !isLoaded || nativeAd == null) return const SizedBox();
    return Padding(
      padding: const EdgeInsets.all(5),
      child: SizedBox(
        height: height,
        width: double.infinity,
        child: AdWidget(ad: nativeAd),
      ),
    );
  }
}
  • TemplateType.small or .medium selects Google's built-in layout.
  • NativeTemplateStyle sets the background, button text and text styles.
  • The widget returns an empty SizedBox until the ad has loaded, so nothing broken shows.

2. The Screen

dart
// lib/screen_native_ads.dart
import 'package:flutter/material.dart';

import 'admob/native_ad_helper.dart';

class ScreenNativeAds extends StatefulWidget {
  const ScreenNativeAds({super.key});

  @override
  State<ScreenNativeAds> createState() => _ScreenNativeAdsState();
}

class _ScreenNativeAdsState extends State<ScreenNativeAds> {
  final nativeAdHelper = NativeAdHelper();

  @override
  void initState() {
    super.initState();
    nativeAdHelper.loadNativeAd(() {
      if (mounted) setState(() {});
    });
  }

  @override
  void dispose() {
    nativeAdHelper.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Native Ad Example')),
      body: Column(
        children: [
          const Expanded(child: Center(child: Text('Main content goes here'))),
          NativeAdHelper.getNativeAdView(
            isPurchase: false,
            isLoaded: nativeAdHelper.isLoaded,
            nativeAd: nativeAdHelper.nativeAd,
            height: 120,
          ),
        ],
      ),
    );
  }
}
  • The ad sits under the content with height: 120.
  • A native ad must have a bounded height; an unbounded AdWidget in a Column throws a layout error.
  • A medium template needs more height (about 350).

Code Examples

Example 1 — Medium Template

dart
nativeAdHelper.loadNativeAd(() {
  if (mounted) setState(() {});
}, type: TemplateType.medium);

and give the view height: 350.


Common Beginner Mistakes

1. No height — the ad throws a layout error.

2. Not disposing — memory leak.

3. Hiding the "Ad" label or disguising the ad as content — against policy; the template keeps the label.


Best Practices

  • Match colours to your theme
  • Give the ad a fixed height
  • Place it between content, not over buttons

Mini Challenge

Show the ad with TemplateType.medium and a taller box, and compare earnings potential in the dashboard later.


Practice Questions

  1. What does the template style control?
  2. Why is a fixed height needed?
  3. What is shown before the ad loads?
  4. What must you do in dispose?

Practice Answers

  1. Colours, fonts and layout type.
  2. The ad view needs bounded size inside a Column.
  3. Nothing (SizedBox).
  4. Dispose the ad.

Key Takeaways

  • Native ads follow your design
  • Fixed height; dispose them
  • Never hide the ad label