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 19+ | 12.0+ |
This package is still in development.
Implementing IMA client-side involves five main SDK components, which are demonstrated in this guide:
This guide demonstrates how to integrate the IMA SDK into a new Widget
using the video_player plugin to display content.
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"/>
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';
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> { // IMA sample tag for a single skippable 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/single_preroll_skippable&sz=640x480&ciu_szs=300x250%2C728x90&gdfp_req=1&output=vast&unviewed_position_start=1&env=vp&impl=s&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 = true; // Controls the content video player. late final VideoPlayerController _contentVideoController; // ··· @override Widget build(BuildContext context) { // ··· } }
Instantiate the AdDisplayContainer for playing Ads and the VideoPlayerController for playing content.
late final AdDisplayContainer _adDisplayContainer = AdDisplayContainer( onContainerAdded: (AdDisplayContainer container) { // 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(() {}); }); }
build
MethodReturn 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, ); }
Handle requesting ads and add event listeners to handle when content should be displayed or hidden.
Future<void> _requestAds(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}'); 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: } }, onAdErrorEvent: (AdErrorEvent event) { debugPrint('AdErrorEvent: ${event.error.message}'); _resumeContent(); }, )); manager.init(); }, onAdsLoadError: (AdsLoadErrorData data) { debugPrint('OnAdsLoadError: ${data.error.message}'); _resumeContent(); }, ); return _adsLoader.requestAds(AdsRequest(adTagUrl: _adTagUrl)); } Future<void> _resumeContent() { setState(() { _shouldShowContentVideo = true; }); return _contentVideoController.play(); } Future<void> _pauseContent() { setState(() { _shouldShowContentVideo = false; }); return _contentVideoController.pause(); }
Dispose the content player and the destroy the AdsManager.
@override void dispose() { super.dispose(); _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.