-
Notifications
You must be signed in to change notification settings - Fork 29.7k
Description
Description:
Hi. We’re having an issue with ads in the video.
We followed the example from pub.dev and are using the latest SDK version.
Here’s the critical problem:
• In debug mode, everything works fine. I can see all AdsManagerDelegate events in the logs, and everything fires as expected.
• In release mode (regardless of the flavor), not all AdsManagerDelegate events not fired. Due of this, some crucial cases—like handling ad completion—don’t trigger.
Also, after closing the ad (either by skipping or when it ends), the ad manager isn’t fully destroyed. I can tell because the video player’s control buttons become unclickable—almost like there’s an invisible widget blocking interactions.
I tried different things—moving managers around, checking if they get destroyed too early—but that’s not the issue. Something inside the library is preventing certain events from coming through in release mode.
Also I tried example code - same issue.
Android - all works and all events fired as expected (both modes Debug\Release)
Thanks!
iOS
Debug mode:
flutter: OnAdEvent: AdEventType.loaded => {}
flutter: OnAdEvent: AdEventType.contentPauseRequested => {}
flutter: OnAdEvent: AdEventType.started => {}
flutter: OnAdEvent: AdEventType.firstQuartile => {}
flutter: OnAdEvent: AdEventType.midpoint => {}
flutter: OnAdEvent: AdEventType.thirdQuartile => {}
flutter: OnAdEvent: AdEventType.complete => {}
flutter: OnAdEvent: AdEventType.contentResumeRequested => {}
flutter: OnAdEvent: AdEventType.loaded => {}
flutter: OnAdEvent: AdEventType.contentPauseRequested => {}
flutter: OnAdEvent: AdEventType.started => {}
flutter: OnAdEvent: AdEventType.firstQuartile => {}
flutter: OnAdEvent: AdEventType.midpoint => {}
flutter: OnAdEvent: AdEventType.thirdQuartile => {}
flutter: OnAdEvent: AdEventType.complete => {}
flutter: OnAdEvent: AdEventType.contentResumeRequested => {}
flutter: OnAdEvent: AdEventType.loaded => {}
flutter: OnAdEvent: AdEventType.contentPauseRequested => {}
flutter: OnAdEvent: AdEventType.started => {}
flutter: OnAdEvent: AdEventType.firstQuartile => {}
flutter: OnAdEvent: AdEventType.midpoint => {}
flutter: OnAdEvent: AdEventType.thirdQuartile => {}
flutter: OnAdEvent: AdEventType.complete => {}
flutter: OnAdEvent: AdEventType.contentResumeRequested => {}
flutter: OnAdEvent: AdEventType.allAdsCompleted => {}
Release mode:
flutter: OnAdEvent: AdEventType.loaded => {}
flutter: OnAdEvent: AdEventType.contentPauseRequested => {}
flutter: OnAdEvent: AdEventType.started => {}
flutter: OnAdEvent: AdEventType.firstQuartile => {}
flutter: OnAdEvent: AdEventType.midpoint => {}
flutter: OnAdEvent: AdEventType.thirdQuartile => {}
flutter: OnAdEvent: AdEventType.complete => {}
flutter: OnAdEvent: AdEventType.contentResumeRequested => {}
On the second video from example code, it stops playing, and a Google ad (10-sec pre-roll) starts playing in the background again.
Also, during the second video, a Google ad (10-sec pre-roll) was playing in the background.
Android (Debug/Release modes): All works as expected
Installing build/app/outputs/flutter-apk/app-release.apk...
I/flutter (14632): OnAdEvent: AdEventType.loaded => {}
I/flutter (14632): OnAdEvent: AdEventType.contentPauseRequested => {}
I/flutter (14632): OnAdEvent: AdEventType.started => {}
I/flutter (14632): OnAdEvent: AdEventType.adProgress => {}
I/flutter (14632): OnAdEvent: AdEventType.firstQuartile => {}
I/flutter (14632): OnAdEvent: AdEventType.adProgress => {}
I/flutter (14632): OnAdEvent: AdEventType.midpoint => {}
I/flutter (14632): OnAdEvent: AdEventType.adProgress => {}
I/flutter (14632): OnAdEvent: AdEventType.thirdQuartile => {}
I/flutter (14632): OnAdEvent: AdEventType.adProgress => {}
I/flutter (14632): OnAdEvent: AdEventType.complete => {}
I/flutter (14632): OnAdEvent: AdEventType.contentResumeRequested => {}
I/flutter (14632): OnAdEvent: AdEventType.loaded => {}
I/flutter (14632): OnAdEvent: AdEventType.contentPauseRequested => {}
I/flutter (14632): OnAdEvent: AdEventType.started => {}
I/flutter (14632): OnAdEvent: AdEventType.adProgress => {}
I/flutter (14632): OnAdEvent: AdEventType.firstQuartile => {}
I/flutter (14632): OnAdEvent: AdEventType.adProgress => {}
I/flutter (14632): OnAdEvent: AdEventType.midpoint => {}
I/flutter (14632): OnAdEvent: AdEventType.adProgress => {}
I/flutter (14632): OnAdEvent: AdEventType.thirdQuartile => {}
I/flutter (14632): OnAdEvent: AdEventType.adProgress => {}
I/flutter (14632): OnAdEvent: AdEventType.complete => {}
I/flutter (14632): OnAdEvent: AdEventType.contentResumeRequested => {}
I/flutter (14632): OnAdEvent: AdEventType.loaded => {}
I/flutter (14632): OnAdEvent: AdEventType.contentPauseRequested => {}
I/flutter (14632): OnAdEvent: AdEventType.started => {}
I/flutter (14632): OnAdEvent: AdEventType.adProgress => {}
I/flutter (14632): OnAdEvent: AdEventType.firstQuartile => {}
I/flutter (14632): OnAdEvent: AdEventType.adProgress => {}
I/flutter (14632): OnAdEvent: AdEventType.midpoint => {}
I/flutter (14632): OnAdEvent: AdEventType.adProgress => {}
I/flutter (14632): OnAdEvent: AdEventType.thirdQuartile => {}
I/flutter (14632): OnAdEvent: AdEventType.adProgress => {}
I/flutter (14632): OnAdEvent: AdEventType.complete => {}
I/flutter (14632): OnAdEvent: AdEventType.contentResumeRequested => {}
I/flutter (14632): OnAdEvent: AdEventType.allAdsCompleted => {}
Example:
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:interactive_media_ads/interactive_media_ads.dart';
import 'package:video_player/video_player.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const AdExampleWidget(),
);
}
}
class AdExampleWidget extends StatefulWidget {
const AdExampleWidget({super.key});
@override
State<AdExampleWidget> createState() => _AdExampleWidgetState();
}
class _AdExampleWidgetState extends State<AdExampleWidget>
with WidgetsBindingObserver {
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=';
late final AdsLoader _adsLoader;
AdsManager? _adsManager;
bool _shouldShowContentVideo = false;
late final VideoPlayerController _contentVideoController;
Timer? _contentProgressTimer;
final ContentProgressProvider _contentProgressProvider =
ContentProgressProvider();
@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((_) {
setState(() {});
});
}
@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>[
_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,
);
}
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();
},
);
_requestAds(container);
},
);
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();
}
}
flutter doctor -v
[✓] Flutter (Channel stable, 3.24.4, on macOS 14.1.1 23B81 darwin-arm64, locale en-IL)
• Flutter version 3.24.4 on channel stable at /Users/sergeykrasiuk/Flutter
• Upstream repository https://github.com/flutter/flutter.git
• Framework revision 603104015d (4 months ago), 2024-10-24 08:01:25 -0700
• Engine revision db49896cf2
• Dart version 3.5.4
• DevTools version 2.37.3
[✓] Android toolchain - develop for Android devices (Android SDK version 34.0.0)
• Android SDK at /Users/sergeykrasiuk/Library/Android/sdk
• Platform android-34, build-tools 34.0.0
• Java binary at: /Library/Java/JavaVirtualMachines/openjdk-17.jdk/Contents/Home/bin/java
• Java version OpenJDK Runtime Environment Homebrew (build 17.0.13+0)
• All Android licenses accepted.
[✓] Xcode - develop for iOS and macOS (Xcode 15.4)
• Xcode at /Applications/Xcode.app/Contents/Developer
• Build 15F31d
• CocoaPods version 1.15.0
[✓] Chrome - develop for the web
• Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome
[✓] Android Studio (version 2024.2)
• Android Studio at /Applications/Android Studio.app/Contents
• Flutter plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/9212-flutter
• Dart plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/6351-dart
• Java version OpenJDK Runtime Environment (build 21.0.3+-79915917-b509.11)
[✓] VS Code (version 1.96.3)
• VS Code at /Applications/Development/Visual Studio Code.app/Contents
• Flutter extension version 3.102.0
[✓] Connected device (7 available)
***
[✓] Network resources
• All expected network resources are available.
• No issues found!