Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
100 commits
Select commit Hold shift + click to select a range
9f02730
get libraries to generate
bparrishMines Apr 26, 2024
5f767fb
add a bunch of classes
bparrishMines Apr 26, 2024
b3317a0
some more videview stuff
bparrishMines Apr 26, 2024
631c1e0
some display implementation for android
bparrishMines Apr 27, 2024
35a4445
add the minimum required wrappings
bparrishMines Apr 29, 2024
8ac0311
fix build error
bparrishMines Apr 29, 2024
bc4d770
implement other platform classes
bparrishMines Apr 30, 2024
1f74ead
start creating an implementation
bparrishMines Apr 30, 2024
4320f50
move interfaces to bottom and format
bparrishMines Apr 30, 2024
e85027d
fix callback events
bparrishMines May 6, 2024
6739d7f
remove prints
bparrishMines May 7, 2024
e803962
fix removeStrongReference error
bparrishMines May 7, 2024
0d59a8e
Merge branch 'main' of github.com:flutter/packages into ima_android
bparrishMines May 9, 2024
6b22ebc
also send time updates
bparrishMines May 9, 2024
957e2ba
combine implementation files
bparrishMines May 9, 2024
d0be873
fix lint warnings
bparrishMines May 9, 2024
875d6be
fix Android dartPluginClass
bparrishMines May 9, 2024
0122f6c
fix missing params call
bparrishMines May 9, 2024
d0971db
make tracking ad progress in ad display container
bparrishMines May 10, 2024
6b8ee3a
Merge branch 'main' of github.com:flutter/packages into ima_android
bparrishMines May 14, 2024
b1ace40
add missing error codes
bparrishMines May 14, 2024
cc728d2
discard ad break
bparrishMines May 14, 2024
f345071
licenses
bparrishMines May 14, 2024
90965aa
copyright header
bparrishMines May 14, 2024
93c239b
first test file
bparrishMines May 14, 2024
c1b00f1
working tests
bparrishMines May 14, 2024
dce1723
more working tests
bparrishMines May 14, 2024
76af339
more tests
bparrishMines May 14, 2024
c2d6f67
media player test
bparrishMines May 14, 2024
9dde9d6
Merge branch 'main' of github.com:flutter/packages into ima_android
bparrishMines May 14, 2024
15aa049
some more tests
bparrishMines May 14, 2024
7c3dc18
finish platform unit tests
bparrishMines May 14, 2024
48c7a42
switch tests to use TestProxyApiRegistrar
bparrishMines May 14, 2024
c5842ad
fix ad size
bparrishMines May 14, 2024
8157448
version bump
bparrishMines May 15, 2024
37fce6f
fix name
bparrishMines May 15, 2024
f00caf2
remove pigeon bro
bparrishMines May 15, 2024
979ad8c
Merge branch 'main' of github.com:flutter/packages into ima_android
bparrishMines May 15, 2024
bdac900
start proxy
bparrishMines May 15, 2024
9250e8d
Merge branch 'main' of github.com:flutter/packages into ima_android
bparrishMines May 16, 2024
1dc6a07
change calls to proxy
bparrishMines May 16, 2024
713bdbd
remove pigeon
bparrishMines May 16, 2024
828ea3a
documentation
bparrishMines May 16, 2024
b4e8cda
fix key and some cleanup
bparrishMines May 16, 2024
c25d360
working addisplaycontainer test
bparrishMines May 16, 2024
849ca63
erge branch 'main' of github.com:flutter/packages into ima_android
bparrishMines May 17, 2024
b182af5
onerror and oncompletion test
bparrishMines May 19, 2024
e2fb27e
on prepared test
bparrishMines May 19, 2024
48fb4de
pause ad and play ad tests
bparrishMines May 19, 2024
0bbba9a
assert and tests
bparrishMines May 20, 2024
1ce77c1
request ads and onAdsLoaded test
bparrishMines May 20, 2024
c7a320e
finish tests
bparrishMines May 20, 2024
a558a54
finish basic tests
bparrishMines May 20, 2024
1c3a2c2
finish all tests
bparrishMines May 20, 2024
428ecec
formatting
bparrishMines May 20, 2024
e8d822c
Merge branch 'main' of github.com:flutter/packages into ima_android
bparrishMines May 20, 2024
5311d85
version bump and license
bparrishMines May 20, 2024
ba23b1d
lower kotlin version
bparrishMines May 20, 2024
52a2c49
try fix lint
bparrishMines May 20, 2024
f32e74f
update generated kotlin
bparrishMines May 20, 2024
75957f2
override pigeonRegistrar type
bparrishMines May 20, 2024
6743d69
make platform classes base to be mockable
bparrishMines May 20, 2024
3edc221
separate some logic
bparrishMines May 20, 2024
3893efe
separate class implementations
bparrishMines May 20, 2024
1c5fac7
Merge branch 'main' of github.com:flutter/packages into ima_android
bparrishMines May 20, 2024
a30c9fc
doc improvements
bparrishMines May 20, 2024
8fa430b
lower meta version to 1.12.0
bparrishMines May 20, 2024
220e2f0
move meta to 1.10.0
bparrishMines May 20, 2024
f55805f
only null ad duration on stop and error
bparrishMines May 21, 2024
284098a
stop any ad tracking before starting a new one
bparrishMines May 21, 2024
69e088c
Merge branch 'main' of github.com:flutter/packages into ima_android
bparrishMines May 21, 2024
48828e3
Merge branch 'main' of github.com:flutter/packages into ima_android
bparrishMines May 22, 2024
891f4d4
stop ad progress tracking on video completion
bparrishMines May 22, 2024
9ada3ef
change generated kotlin library name
bparrishMines May 30, 2024
84d1ff5
docs for kotlin classes
bparrishMines May 30, 2024
1abcabc
Merge branch 'main' of github.com:flutter/packages into ima_android
bparrishMines May 30, 2024
b4b2152
variable docs
bparrishMines May 31, 2024
519c68e
beef up docs and some formatting
bparrishMines May 31, 2024
f7d25c6
Merge branch 'main' of github.com:flutter/packages into ima_android
bparrishMines May 31, 2024
8923d5f
uncomment pigeon file
bparrishMines Jun 1, 2024
9145273
an
bparrishMines Jun 2, 2024
c3ce374
add an unknown value for enum
bparrishMines Jun 3, 2024
5e11462
Merge branch 'main' of github.com:flutter/packages into ima_android
bparrishMines Jun 3, 2024
24f0baa
Merge branch 'main' of github.com:flutter/packages into ima_android
bparrishMines Jun 25, 2024
dc6f38a
comment pigeon
bparrishMines Jun 25, 2024
819441a
add flutter request agent
bparrishMines Jun 25, 2024
eda9cac
request agent test
bparrishMines Jun 25, 2024
6a18fac
formatting and lint
bparrishMines Jun 25, 2024
4829c85
only run example on Android
bparrishMines Jun 25, 2024
463bfe4
small nits
bparrishMines Jun 25, 2024
ca22c23
Merge branch 'main' of github.com:flutter/packages into ima_readme
bparrishMines Jun 25, 2024
0a7bebd
update readme and some bad docs
bparrishMines Jun 25, 2024
98bb920
version bump
bparrishMines Jun 25, 2024
1605042
actually count and mention pubspec
bparrishMines Jun 25, 2024
f8677d3
fix counts and other thing
bparrishMines Jun 25, 2024
c939551
some more readme fixes
bparrishMines Jun 25, 2024
fa53978
improve docs some
bparrishMines Jun 25, 2024
de84612
five not four
bparrishMines Jun 25, 2024
b37e4f6
fix changelog
bparrishMines Jun 25, 2024
9aea125
review comments
bparrishMines Jun 27, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions packages/interactive_media_ads/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 0.0.2+1

* Updates `README` with a usage section and fix app-facing interface documentation.

## 0.0.2

* Adds Android implementation.
Expand Down
264 changes: 263 additions & 1 deletion packages/interactive_media_ads/README.md
Copy link
Contributor Author

@bparrishMines bparrishMines Jun 25, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,274 @@ Flutter plugin for the [Interactive Media Ads SDKs][1].

[![pub package](https://img.shields.io/pub/v/interactive_media_ads.svg)](https://pub.dev/packages/interactive_media_ads)

A Flutter plugin for using the Interactive Media Ads SDKs on Android and iOS.
IMA SDKs make it easy to integrate multimedia ads into your websites and apps. IMA SDKs can request
ads from any [VAST-compliant][2] 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.**

## IMA client-side overview

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

* [AdDisplayContainer][3]: A container object where ads are rendered.
* [AdsLoader][4]: 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][5]: 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][6]: Contains the response to the ads request, controls ad playback,
and listens for ad events fired by the SDK.
* [AdsManagerDelegate][8]: Handles ad events and errors that occur during ad or stream
initialization and playback.

## Usage

This guide demonstrates how to integrate the IMA SDK into a new `Widget` using the [video_player][7]
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
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you are going to use a bulleted list for the headings, I would make all of the content part of the list (by indenting everything in this entire section by two spaces), so that the content of each section isn't offset further left than its heading.

Alternatively, you could do ### 1. Add Android Required Permissions, etc.

`android/app/src/main/AndroidManifest.xml`.

<?code-excerpt "example/android/app/src/main/AndroidManifest.xml (android_manifest)"?>
```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][7]. Both plugins should
already be added to your `pubspec.yaml`.

<?code-excerpt "example/lib/main.dart (imports)"?>
```dart
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](https://api.flutter.dev/flutter/widgets/StatefulWidget-class.html)
that handles displaying Ads and playing content.

<?code-excerpt "example/lib/main.dart (example_widget)"?>
```dart
/// 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) {
// ···
}
}
```

### 4. Add the Video Players

Instantiate the [AdDisplayContainer][3] for playing Ads and the
[VideoPlayerController](https://pub.dev/documentation/video_player/latest/video_player/VideoPlayerController-class.html)
for playing content.

<?code-excerpt "example/lib/main.dart (ad_and_content_players)"?>
```dart
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(() {});
});
}
```

### 5. Implement the `build` Method

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

<?code-excerpt "example/lib/main.dart (widget_build)"?>
```dart
@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.

<?code-excerpt "example/lib/main.dart (request_ads)"?>
```dart
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();
}
```

### 7. Dispose Resources

Dispose the content player and the destroy the [AdsManager][6].

<?code-excerpt "example/lib/main.dart (dispose)"?>
```dart
@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](https://pub.dev/documentation/interactive_media_ads/latest/).

[1]: https://developers.google.com/interactive-media-ads
[2]: https://www.iab.com/guidelines/vast/
[3]: https://pub.dev/documentation/interactive_media_ads/latest/interactive_media_ads/AdDisplayContainer-class.html
[4]: https://pub.dev/documentation/interactive_media_ads/latest/interactive_media_ads/AdsLoader-class.html
[5]: https://pub.dev/documentation/interactive_media_ads/latest/interactive_media_ads/AdsRequest-class.html
[6]: https://pub.dev/documentation/interactive_media_ads/latest/interactive_media_ads/AdsManager-class.html
[7]: https://pub.dev/packages/video_player
[8]: https://pub.dev/documentation/interactive_media_ads/latest/interactive_media_ads/AdsManagerDelegate-class.html
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class AdsRequestProxyApi(override val pigeonRegistrar: ProxyApiRegistrar) :
*
* This must match the version in pubspec.yaml.
*/
const val pluginVersion = "0.0.2"
const val pluginVersion = "0.0.2+1"
}

override fun setAdTagUrl(pigeon_instance: AdsRequest, adTagUrl: String) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
<!--#docregion android_manifest-->
<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"/>

<!--#enddocregion android_manifest-->
<application
android:label="interactive_media_ads_example"
android:name="${applicationName}"
Expand Down
Loading