@@ -4,12 +4,274 @@ Flutter plugin for the [Interactive Media Ads SDKs][1].
4
4
5
5
[ ![ pub package] ( https://img.shields.io/pub/v/interactive_media_ads.svg )] ( https://pub.dev/packages/interactive_media_ads )
6
6
7
- A Flutter plugin for using the Interactive Media Ads SDKs on Android and iOS.
7
+ IMA SDKs make it easy to integrate multimedia ads into your websites and apps. IMA SDKs can request
8
+ ads from any [ VAST-compliant] [ 2 ] ad server and manage ad playback in your apps. With IMA client-side
9
+ SDKs, you maintain control of content video playback, while the SDK handles ad playback. Ads play in
10
+ a separate video player positioned on top of the app's content video player.
8
11
9
12
| | Android | iOS |
10
13
| -------------| ---------| -------|
11
14
| ** Support** | SDK 19+ | 12.0+ |
12
15
13
16
** This package is still in development.**
14
17
18
+ ## IMA client-side overview
19
+
20
+ Implementing IMA client-side involves five main SDK components, which are demonstrated in this
21
+ guide:
22
+
23
+ * [ AdDisplayContainer] [ 3 ] : A container object where ads are rendered.
24
+ * [ AdsLoader] [ 4 ] : Requests ads and handles events from ads request responses. You should only
25
+ instantiate one ads loader, which can be reused throughout the life of the application.
26
+ * [ AdsRequest] [ 5 ] : An object that defines an ads request. Ads requests specify the URL for the VAST
27
+ ad tag, as well as additional parameters, such as ad dimensions.
28
+ * [ AdsManager] [ 6 ] : Contains the response to the ads request, controls ad playback,
29
+ and listens for ad events fired by the SDK.
30
+ * [ AdsManagerDelegate] [ 8 ] : Handles ad events and errors that occur during ad or stream
31
+ initialization and playback.
32
+
33
+ ## Usage
34
+
35
+ This guide demonstrates how to integrate the IMA SDK into a new ` Widget ` using the [ video_player] [ 7 ]
36
+ plugin to display content.
37
+
38
+ ### 1. Add Android Required Permissions
39
+
40
+ If building on Android, add the user permissions required by the IMA SDK for requesting ads in
41
+ ` android/app/src/main/AndroidManifest.xml ` .
42
+
43
+ <? code-excerpt "example/android/app/src/main/AndroidManifest.xml (android_manifest)"?>
44
+ ``` xml
45
+ <manifest xmlns : android =" http://schemas.android.com/apk/res/android" >
46
+ <!-- Required permissions for the IMA SDK -->
47
+ <uses-permission android : name =" android.permission.INTERNET" />
48
+ <uses-permission android : name =" android.permission.ACCESS_NETWORK_STATE" />
49
+ ```
50
+
51
+ ### 2. Add Imports
52
+
53
+ Add the import statements for the ` interactive_media_ads ` and [ video_player] [ 7 ] . Both plugins should
54
+ already be added to your ` pubspec.yaml ` .
55
+
56
+ <? code-excerpt "example/lib/main.dart (imports)"?>
57
+ ``` dart
58
+ import 'package:interactive_media_ads/interactive_media_ads.dart';
59
+ import 'package:video_player/video_player.dart';
60
+ ```
61
+
62
+ ### 3. Create a New Widget
63
+
64
+ Create a new [ StatefulWidget] ( https://api.flutter.dev/flutter/widgets/StatefulWidget-class.html )
65
+ that handles displaying Ads and playing content.
66
+
67
+ <? code-excerpt "example/lib/main.dart (example_widget)"?>
68
+ ``` dart
69
+ /// Example widget displaying an Ad before a video.
70
+ class AdExampleWidget extends StatefulWidget {
71
+ /// Constructs an [AdExampleWidget].
72
+ const AdExampleWidget({super.key});
73
+
74
+ @override
75
+ State<AdExampleWidget> createState() => _AdExampleWidgetState();
76
+ }
77
+
78
+ class _AdExampleWidgetState extends State<AdExampleWidget> {
79
+ // IMA sample tag for a single skippable inline video ad. See more IMA sample
80
+ // tags at https://developers.google.com/interactive-media-ads/docs/sdks/html5/client-side/tags
81
+ static const String _adTagUrl =
82
+ '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=';
83
+
84
+ // The AdsLoader instance exposes the request ads method.
85
+ late final AdsLoader _adsLoader;
86
+
87
+ // AdsManager exposes methods to control ad playback and listen to ad events.
88
+ AdsManager? _adsManager;
89
+
90
+ // Whether the widget should be displaying the content video. The content
91
+ // player is hidden while Ads are playing.
92
+ bool _shouldShowContentVideo = true;
93
+
94
+ // Controls the content video player.
95
+ late final VideoPlayerController _contentVideoController;
96
+ // ···
97
+ @override
98
+ Widget build(BuildContext context) {
99
+ // ···
100
+ }
101
+ }
102
+ ```
103
+
104
+ ### 4. Add the Video Players
105
+
106
+ Instantiate the [ AdDisplayContainer] [ 3 ] for playing Ads and the
107
+ [ VideoPlayerController] ( https://pub.dev/documentation/video_player/latest/video_player/VideoPlayerController-class.html )
108
+ for playing content.
109
+
110
+ <? code-excerpt "example/lib/main.dart (ad_and_content_players)"?>
111
+ ``` dart
112
+ late final AdDisplayContainer _adDisplayContainer = AdDisplayContainer(
113
+ onContainerAdded: (AdDisplayContainer container) {
114
+ // Ads can't be requested until the `AdDisplayContainer` has been added to
115
+ // the native View hierarchy.
116
+ _requestAds(container);
117
+ },
118
+ );
119
+
120
+ @override
121
+ void initState() {
122
+ super.initState();
123
+ _contentVideoController = VideoPlayerController.networkUrl(
124
+ Uri.parse(
125
+ 'https://storage.googleapis.com/gvabox/media/samples/stock.mp4',
126
+ ),
127
+ )
128
+ ..addListener(() {
129
+ if (_contentVideoController.value.isCompleted) {
130
+ _adsLoader.contentComplete();
131
+ setState(() {});
132
+ }
133
+ })
134
+ ..initialize().then((_) {
135
+ // Ensure the first frame is shown after the video is initialized, even before the play button has been pressed.
136
+ setState(() {});
137
+ });
138
+ }
139
+ ```
140
+
141
+ ### 5. Implement the ` build ` Method
142
+
143
+ Return a ` Widget ` that contains the ad player and the content player.
144
+
145
+ <? code-excerpt "example/lib/main.dart (widget_build)"?>
146
+ ``` dart
147
+ @override
148
+ Widget build(BuildContext context) {
149
+ return Scaffold(
150
+ body: Center(
151
+ child: SizedBox(
152
+ width: 300,
153
+ child: !_contentVideoController.value.isInitialized
154
+ ? Container()
155
+ : AspectRatio(
156
+ aspectRatio: _contentVideoController.value.aspectRatio,
157
+ child: Stack(
158
+ children: <Widget>[
159
+ // The display container must be on screen before any Ads can be
160
+ // loaded and can't be removed between ads. This handles clicks for
161
+ // ads.
162
+ _adDisplayContainer,
163
+ if (_shouldShowContentVideo)
164
+ VideoPlayer(_contentVideoController)
165
+ ],
166
+ ),
167
+ ),
168
+ ),
169
+ ),
170
+ floatingActionButton:
171
+ _contentVideoController.value.isInitialized && _shouldShowContentVideo
172
+ ? FloatingActionButton(
173
+ onPressed: () {
174
+ setState(() {
175
+ _contentVideoController.value.isPlaying
176
+ ? _contentVideoController.pause()
177
+ : _contentVideoController.play();
178
+ });
179
+ },
180
+ child: Icon(
181
+ _contentVideoController.value.isPlaying
182
+ ? Icons.pause
183
+ : Icons.play_arrow,
184
+ ),
185
+ )
186
+ : null,
187
+ );
188
+ }
189
+ ```
190
+
191
+ ### 6. Request Ads
192
+
193
+ Handle requesting ads and add event listeners to handle when content should be displayed or hidden.
194
+
195
+ <? code-excerpt "example/lib/main.dart (request_ads)"?>
196
+ ``` dart
197
+ Future<void> _requestAds(AdDisplayContainer container) {
198
+ _adsLoader = AdsLoader(
199
+ container: container,
200
+ onAdsLoaded: (OnAdsLoadedData data) {
201
+ final AdsManager manager = data.manager;
202
+ _adsManager = data.manager;
203
+
204
+ manager.setAdsManagerDelegate(AdsManagerDelegate(
205
+ onAdEvent: (AdEvent event) {
206
+ debugPrint('OnAdEvent: ${event.type}');
207
+ switch (event.type) {
208
+ case AdEventType.loaded:
209
+ manager.start();
210
+ case AdEventType.contentPauseRequested:
211
+ _pauseContent();
212
+ case AdEventType.contentResumeRequested:
213
+ _resumeContent();
214
+ case AdEventType.allAdsCompleted:
215
+ manager.destroy();
216
+ _adsManager = null;
217
+ case AdEventType.clicked:
218
+ case AdEventType.complete:
219
+ }
220
+ },
221
+ onAdErrorEvent: (AdErrorEvent event) {
222
+ debugPrint('AdErrorEvent: ${event.error.message}');
223
+ _resumeContent();
224
+ },
225
+ ));
226
+
227
+ manager.init();
228
+ },
229
+ onAdsLoadError: (AdsLoadErrorData data) {
230
+ debugPrint('OnAdsLoadError: ${data.error.message}');
231
+ _resumeContent();
232
+ },
233
+ );
234
+
235
+ return _adsLoader.requestAds(AdsRequest(adTagUrl: _adTagUrl));
236
+ }
237
+
238
+ Future<void> _resumeContent() {
239
+ setState(() {
240
+ _shouldShowContentVideo = true;
241
+ });
242
+ return _contentVideoController.play();
243
+ }
244
+
245
+ Future<void> _pauseContent() {
246
+ setState(() {
247
+ _shouldShowContentVideo = false;
248
+ });
249
+ return _contentVideoController.pause();
250
+ }
251
+ ```
252
+
253
+ ### 7. Dispose Resources
254
+
255
+ Dispose the content player and the destroy the [ AdsManager] [ 6 ] .
256
+
257
+ <? code-excerpt "example/lib/main.dart (dispose)"?>
258
+ ``` dart
259
+ @override
260
+ void dispose() {
261
+ super.dispose();
262
+ _contentVideoController.dispose();
263
+ _adsManager?.destroy();
264
+ }
265
+ ```
266
+
267
+ That's it! You're now requesting and displaying ads with the IMA SDK. To learn about additional SDK
268
+ features, see the [ API reference] ( https://pub.dev/documentation/interactive_media_ads/latest/ ) .
269
+
15
270
[ 1 ] : https://developers.google.com/interactive-media-ads
271
+ [ 2 ] : https://www.iab.com/guidelines/vast/
272
+ [ 3 ] : https://pub.dev/documentation/interactive_media_ads/latest/interactive_media_ads/AdDisplayContainer-class.html
273
+ [ 4 ] : https://pub.dev/documentation/interactive_media_ads/latest/interactive_media_ads/AdsLoader-class.html
274
+ [ 5 ] : https://pub.dev/documentation/interactive_media_ads/latest/interactive_media_ads/AdsRequest-class.html
275
+ [ 6 ] : https://pub.dev/documentation/interactive_media_ads/latest/interactive_media_ads/AdsManager-class.html
276
+ [ 7 ] : https://pub.dev/packages/video_player
277
+ [ 8 ] : https://pub.dev/documentation/interactive_media_ads/latest/interactive_media_ads/AdsManagerDelegate-class.html
0 commit comments