interactive_media_ads 0.2.3+12
interactive_media_ads: ^0.2.3+12 copied to clipboard

A Flutter plugin for using the Interactive Media Ads SDKs on Android and iOS.

interactive_media_ads #

Flutter plugin for the Interactive Media Ads SDKs.

IMA SDKs make it easy to integrate multimedia ads into your websites and apps. IMA SDKs can request ads from any VAST-compliant ad server and manage ad playback in your apps. With IMA client-side SDKs, you maintain control of content video playback, while the SDK handles ad playback. Ads play in a separate video player positioned on top of the app's content video player.

Android iOS
Support SDK 21+ 12.0+

NOTE:

  • Companion ads, Background Audio ads and Google Dynamic Ad Insertion methods are currently not supported.

IMA client-side overview #

Image for: IMA client-side overview #

Implementing IMA client-side involves five main SDK components, which are demonstrated in this guide:

  • AdDisplayContainer: A container object where ads are rendered.
  • AdsLoader: Requests ads and handles events from ads request responses. You should only instantiate one ads loader, which can be reused throughout the life of the application.
  • AdsRequest: An object that defines an ads request. Ads requests specify the URL for the VAST ad tag, as well as additional parameters, such as ad dimensions.
  • AdsManager: Contains the response to the ads request, controls ad playback, and listens for ad events fired by the SDK.
  • AdsManagerDelegate: Handles ad events and errors that occur during ad or stream initialization and playback.

Usage #

Image for: Usage #

This guide demonstrates how to integrate the IMA SDK into a new Widget using the video_player plugin to display content.

1. Add Android Required Permissions #

If building on Android, add the user permissions required by the IMA SDK for requesting ads in android/app/src/main/AndroidManifest.xml.

<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- Required permissions for the IMA SDK -->
    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

2. Add Imports #

Add the import statements for the interactive_media_ads and video_player. Both plugins should already be added to your pubspec.yaml.

import 'package:interactive_media_ads/interactive_media_ads.dart';
import 'package:video_player/video_player.dart';

3. Create a New Widget #

Create a new StatefulWidget that handles displaying Ads and playing content.

/// Example widget displaying an Ad before a video.
class AdExampleWidget extends StatefulWidget {
  /// Constructs an [AdExampleWidget].
  const AdExampleWidget({super.key});

  @override
  State<AdExampleWidget> createState() => _AdExampleWidgetState();
}

class _AdExampleWidgetState extends State<AdExampleWidget>
    with WidgetsBindingObserver {
  // IMA sample tag for a pre-, mid-, and post-roll, single inline video ad. See more IMA sample
  // tags at https://developers.google.com/interactive-media-ads/docs/sdks/html5/client-side/tags
  static const String _adTagUrl =
      'https://pubads.g.doubleclick.net/gampad/ads?iu=/21775744923/external/vmap_ad_samples&sz=640x480&cust_params=sample_ar%3Dpremidpost&ciu_szs=300x250&gdfp_req=1&ad_rule=1&output=vmap&unviewed_position_start=1&env=vp&impl=s&cmsid=496&vid=short_onecue&correlator=';

  // The AdsLoader instance exposes the request ads method.
  late final AdsLoader _adsLoader;

  // AdsManager exposes methods to control ad playback and listen to ad events.
  AdsManager? _adsManager;

  // ···
  // Whether the widget should be displaying the content video. The content
  // player is hidden while Ads are playing.
  bool _shouldShowContentVideo = false;

  // Controls the content video player.
  late final VideoPlayerController _contentVideoController;

  // Periodically updates the SDK of the current playback progress of the
  // content video.
  Timer? _contentProgressTimer;

  // Provides the SDK with the current playback progress of the content video.
  // This is required to support mid-roll ads.
  final ContentProgressProvider _contentProgressProvider =
      ContentProgressProvider();
  // ···
  @override
  Widget build(BuildContext context) {
    // ···
  }
}

4. Add the Video Players #

Instantiate the AdDisplayContainer for playing Ads and the VideoPlayerController for playing content.

late final AdDisplayContainer _adDisplayContainer = AdDisplayContainer(
  onContainerAdded: (AdDisplayContainer container) {
    _adsLoader = AdsLoader(
      container: container,
      onAdsLoaded: (OnAdsLoadedData data) {
        final AdsManager manager = data.manager;
        _adsManager = data.manager;

        manager.setAdsManagerDelegate(AdsManagerDelegate(
          onAdEvent: (AdEvent event) {
            debugPrint('OnAdEvent: ${event.type} => ${event.adData}');
            switch (event.type) {
              case AdEventType.loaded:
                manager.start();
              case AdEventType.contentPauseRequested:
                _pauseContent();
              case AdEventType.contentResumeRequested:
                _resumeContent();
              case AdEventType.allAdsCompleted:
                manager.destroy();
                _adsManager = null;
              case AdEventType.clicked:
              case AdEventType.complete:
              case _:
            }
          },
          onAdErrorEvent: (AdErrorEvent event) {
            debugPrint('AdErrorEvent: ${event.error.message}');
            _resumeContent();
          },
        ));

        manager.init(settings: AdsRenderingSettings(enablePreloading: true));
      },
      onAdsLoadError: (AdsLoadErrorData data) {
        debugPrint('OnAdsLoadError: ${data.error.message}');
        _resumeContent();
      },
    );

    // Ads can't be requested until the `AdDisplayContainer` has been added to
    // the native View hierarchy.
    _requestAds(container);
  },
);

@override
void initState() {
  super.initState();
  // ···
  _contentVideoController = VideoPlayerController.networkUrl(
    Uri.parse(
      'https://storage.googleapis.com/gvabox/media/samples/stock.mp4',
    ),
  )
    ..addListener(() {
      if (_contentVideoController.value.isCompleted) {
        _adsLoader.contentComplete();
      }
      setState(() {});
    })
    ..initialize().then((_) {
      // Ensure the first frame is shown after the video is initialized, even before the play button has been pressed.
      setState(() {});
    });
}

5. Implement the build Method #

Return a Widget that contains the ad player and the content player.

@override
Widget build(BuildContext context) {
  return Scaffold(
    body: Center(
      child: SizedBox(
        width: 300,
        child: !_contentVideoController.value.isInitialized
            ? Container()
            : AspectRatio(
                aspectRatio: _contentVideoController.value.aspectRatio,
                child: Stack(
                  children: <Widget>[
                    // The display container must be on screen before any Ads can be
                    // loaded and can't be removed between ads. This handles clicks for
                    // ads.
                    _adDisplayContainer,
                    if (_shouldShowContentVideo)
                      VideoPlayer(_contentVideoController)
                  ],
                ),
              ),
      ),
    ),
    floatingActionButton:
        _contentVideoController.value.isInitialized && _shouldShowContentVideo
            ? FloatingActionButton(
                onPressed: () {
                  setState(() {
                    _contentVideoController.value.isPlaying
                        ? _contentVideoController.pause()
                        : _contentVideoController.play();
                  });
                },
                child: Icon(
                  _contentVideoController.value.isPlaying
                      ? Icons.pause
                      : Icons.play_arrow,
                ),
              )
            : null,
  );
}

6. Request Ads #

Handle requesting ads and add event listeners to handle when content should be displayed or hidden.

Future<void> _requestAds(AdDisplayContainer container) {
  return _adsLoader.requestAds(AdsRequest(
    adTagUrl: _adTagUrl,
    contentProgressProvider: _contentProgressProvider,
  ));
}

Future<void> _resumeContent() async {
  setState(() {
    _shouldShowContentVideo = true;
  });

  if (_adsManager != null) {
    _contentProgressTimer = Timer.periodic(
      const Duration(milliseconds: 200),
      (Timer timer) async {
        if (_contentVideoController.value.isInitialized) {
          final Duration? progress = await _contentVideoController.position;
          if (progress != null) {
            await _contentProgressProvider.setProgress(
              progress: progress,
              duration: _contentVideoController.value.duration,
            );
          }
        }
      },
    );
  }

  await _contentVideoController.play();
}

Future<void> _pauseContent() {
  setState(() {
    _shouldShowContentVideo = false;
  });
  _contentProgressTimer?.cancel();
  _contentProgressTimer = null;
  return _contentVideoController.pause();
}

7. Dispose Resources #

Dispose the content player and destroy the AdsManager.

@override
void dispose() {
  super.dispose();
  _contentProgressTimer?.cancel();
  _contentVideoController.dispose();
  _adsManager?.destroy();
  // ···
}

That's it! You're now requesting and displaying ads with the IMA SDK. To learn about additional SDK features, see the API reference.

Contributing #

Image for: Contributing #

For information on contributing to this plugin, see CONTRIBUTING.md.

91
likes
150
points
109
downloads

Publisher

labs.flutter.dev

Weekly Downloads

A Flutter plugin for using the Interactive Media Ads SDKs on Android and iOS.

Repository (GitHub)
View/report issues
Contributing

Topics

#ads

Documentation

API reference

License

BSD-3-Clause (license)

Dependencies

flutter, meta

More

Packages that depend on interactive_media_ads