-
Notifications
You must be signed in to change notification settings - Fork 29.7k
Description
What package does this bug report belong to?
interactive_media_ads
What target platforms are you seeing this bug on?
Android
Have you already upgraded your packages?
Yes
Dependency versions
pubspec.lock
[Paste file content here]
Steps to reproduce
take example from package
replace
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=';
with
static const String _adTagUrl = true
? "https://pubads.g.doubleclick.net/gampad/ads?iu=/18294456/AlSumaria_App_VOD_Preroll&description_url=http%3A%2F%2Fwww.alsumaria.tv%2F&tfcd=0&npa=0&sz=640x480&gdfp_req=1&unviewed_position_start=1&output=vast&env=vp&impl=s&correlator="
: '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=';
run app
getting exception
Expected results
ads should displayed
Actual results
000 -> 0x10010000) E/flutter ( 9689): [ERROR:flutter/runtime/dart_vm_initializer.cc(40)] Unhandled Exception: Null check operator used on a null value E/flutter ( 9689): #0 AndroidAdDisplayContainer._setUpVideoAdPlayer.<anonymous closure> (package:interactive_media_ads/src/android/android_ad_display_container.dart:284:39) E/flutter ( 9689): #1 VideoAdPlayer.pigeon_setUpMessageHandlers.<anonymous closure> (package:interactive_media_ads/src/android/interactive_media_ads.g.dart:5634:18) E/flutter ( 9689): #2 BasicMessageChannel.setMessageHandler.<anonymous closure> (package:flutter/src/services/platform_channel.dart:261:49) E/flutter ( 9689): #3 _DefaultBinaryMessenger.setMessageHandler.<anonymous closure> (package:flutter/src/services/binding.dart:650:35) E/flutter ( 9689): #4 _invoke2 (dart:ui/hooks.dart:348:13) E/flutter ( 9689): #5 _ChannelCallbackRecord.invoke (dart:ui/channel_buffers.dart:45:5) E/flutter ( 9689): #6 _Channel.push (dart:ui/channel_buffers.dart:136:31) E/flutter ( 9689): #7 ChannelBuffers.push (dart:ui/channel_buffers.dart:344:17) E/flutter ( 9689): #8 PlatformDispatcher._dispatchPlatformMessage (dart:ui/platform_dispatcher.dart:786:22) E/flutter ( 9689): #9 _dispatchPlatformMessage (dart:ui/hooks.dart:262:31)
Code sample
Code sample
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_driver/driver_extension.dart';
import 'package:interactive_media_ads/interactive_media_ads.dart';
import 'package:video_player/video_player.dart';
/// Entry point for integration tests that require espresso.
@pragma('vm:entry-point')
void integrationTestMain() {
enableFlutterDriverExtension();
main();
}
void main() {
runApp(const MaterialApp(home: AdExampleWidget()));
}
/// 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 = true
? "https://pubads.g.doubleclick.net/gampad/ads?iu=/18294456/AlSumaria_App_VOD_Preroll&description_url=http%3A%2F%2Fwww.alsumaria.tv%2F&tfcd=0&npa=0&sz=640x480&gdfp_req=1&unviewed_position_start=1&output=vast&env=vp&impl=s&correlator="
: '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;
// Last state received in `didChangeAppLifecycleState`.
AppLifecycleState _lastLifecycleState = AppLifecycleState.resumed;
// 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();
late final CompanionAdSlot companionAd = CompanionAdSlot(
size: CompanionAdSlotSize.fixed(width: 300, height: 250),
onClicked: () => debugPrint('Companion Ad Clicked'),
);
late final AdDisplayContainer _adDisplayContainer = AdDisplayContainer(
companionSlots: <CompanionAdSlot>[companionAd],
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();
// Adds this instance as an observer for `AppLifecycleState` changes.
WidgetsBinding.instance.addObserver(this);
_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(() {});
});
}
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
switch (state) {
case AppLifecycleState.resumed:
if (!_shouldShowContentVideo) {
_adsManager?.resume();
}
case AppLifecycleState.inactive:
// Pausing the Ad video player on Android can only be done in this state
// because it corresponds to `Activity.onPause`. This state is also
// triggered before resume, so this will only pause the Ad if the app is
// in the process of being sent to the background.
if (!_shouldShowContentVideo &&
_lastLifecycleState == AppLifecycleState.resumed) {
_adsManager?.pause();
}
case AppLifecycleState.hidden:
case AppLifecycleState.paused:
case AppLifecycleState.detached:
}
_lastLifecycleState = state;
}
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();
}
@override
void dispose() {
super.dispose();
_contentProgressTimer?.cancel();
_contentVideoController.dispose();
_adsManager?.destroy();
WidgetsBinding.instance.removeObserver(this);
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
spacing: 100,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
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)
],
),
),
),
ColoredBox(
color: Colors.green,
child: SizedBox(
width: 300,
height: 250,
child: companionAd.buildWidget(context),
),
),
],
),
),
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,
);
}
}
Screenshots or Videos
Logs
Logs
I/flutter (19534): OnAdEventpreEvent: AdEventType.loaded
I/flutter (19534): OnAdEventpreEvent: AdEventType.contentPauseRequestedFlutter Doctor output
Doctor output
[!] Flutter (Channel stable, 3.32.8, on Microsoft Windows [Version 10.0.26100.4652], locale en-US)
! Warning: `flutter` on your path resolves to C:\Users\Ab-Aziz\fvm\versions\3.32.8\bin\flutter, which is not inside your current Flutter SDK checkout at
C:\Users\Ab-Aziz\fvm\default. Consider adding C:\Users\Ab-Aziz\fvm\default\bin to the front of your path.
! Warning: `dart` on your path resolves to C:\Users\Ab-Aziz\fvm\versions\3.32.8\bin\dart, which is not inside your current Flutter SDK checkout at
C:\Users\Ab-Aziz\fvm\default. Consider adding C:\Users\Ab-Aziz\fvm\default\bin to the front of your path.
[√] Windows Version (11 Pro 64-bit, 24H2, 2009)
[√] Android toolchain - develop for Android devices (Android SDK version 35.0.0)
[√] Chrome - develop for the web
[X] Visual Studio - develop Windows apps
X Visual Studio not installed; this is necessary to develop Windows apps.
Download at https://visualstudio.microsoft.com/downloads/.
Please install the "Desktop development with C++" workload, including all of its default components
[√] Android Studio (version 2024.3)
[√] VS Code (version 1.99.3)
[√] Connected device (4 available)
[√] Network resources
