diff --git a/analysis_options.yaml b/analysis_options.yaml index c61a77070..5bc20088b 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -12,7 +12,12 @@ # See the License for the specific language governing permissions and # limitations under the License. -include: package:pedantic/analysis_options.1.8.0.yaml +include: package:pedantic/analysis_options.1.11.0.yaml + +analyzer: + errors: + omit_local_variable_types: ignore + linter: rules: - public_member_api_docs diff --git a/packages/google_mobile_ads/CHANGELOG.md b/packages/google_mobile_ads/CHANGELOG.md index 2751c6cbb..9658a3604 100644 --- a/packages/google_mobile_ads/CHANGELOG.md +++ b/packages/google_mobile_ads/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.12.0 + +* Migrated to null safety. Minimum Dart SDK version is bumped to 2.12.0. + ## 0.11.0+4 * Fixes a [bug](https://github.com/googleads/googleads-mobile-flutter/issues/47) where state is not properly cleaned up on hot restart. diff --git a/packages/google_mobile_ads/android/src/main/java/io/flutter/plugins/googlemobileads/Constants.java b/packages/google_mobile_ads/android/src/main/java/io/flutter/plugins/googlemobileads/Constants.java index c28d9bae0..f3a3dccd3 100644 --- a/packages/google_mobile_ads/android/src/main/java/io/flutter/plugins/googlemobileads/Constants.java +++ b/packages/google_mobile_ads/android/src/main/java/io/flutter/plugins/googlemobileads/Constants.java @@ -17,5 +17,5 @@ /** Constants used in the plugin. */ public class Constants { /** Version request agent. Should be bumped alongside plugin versions. */ - public static final String REQUEST_AGENT_PREFIX_VERSIONED = "Flutter-GMA-0.11.0+4"; + public static final String REQUEST_AGENT_PREFIX_VERSIONED = "Flutter-GMA-0.12.0"; } diff --git a/packages/google_mobile_ads/example/analysis_options.yaml b/packages/google_mobile_ads/example/analysis_options.yaml new file mode 100644 index 000000000..9b541d2af --- /dev/null +++ b/packages/google_mobile_ads/example/analysis_options.yaml @@ -0,0 +1,15 @@ +# Copyright 2021 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +include: ../../../analysis_options.yaml diff --git a/packages/google_mobile_ads/example/lib/main.dart b/packages/google_mobile_ads/example/lib/main.dart index b5253c4fd..e9f39ae5e 100644 --- a/packages/google_mobile_ads/example/lib/main.dart +++ b/packages/google_mobile_ads/example/lib/main.dart @@ -33,16 +33,16 @@ class MyApp extends StatefulWidget { class _MyAppState extends State { static final AdRequest request = AdRequest( - testDevices: testDevice != null ? [testDevice] : null, + testDevices: [testDevice], keywords: ['foo', 'bar'], contentUrl: 'http://foo.com/bar.html', nonPersonalizedAds: true, ); - InterstitialAd _interstitialAd; + InterstitialAd? _interstitialAd; bool _interstitialReady = false; - RewardedAd _rewardedAd; + RewardedAd? _rewardedAd; bool _rewardedReady = false; @override @@ -54,7 +54,7 @@ class _MyAppState extends State { .updateRequestConfiguration(RequestConfiguration( tagForChildDirectedTreatment: TagForChildDirectedTreatment.unspecified)) - .then((value) { + .then((void value) { createInterstitialAd(); createRewardedAd(); }); @@ -130,7 +130,7 @@ class _MyAppState extends State { Widget build(BuildContext context) { return MaterialApp( home: Builder( - builder: (context) => Scaffold( + builder: (BuildContext context) => Scaffold( appBar: AppBar( title: const Text('AdMob Plugin example app'), actions: [ @@ -139,39 +139,40 @@ class _MyAppState extends State { switch (result) { case 'InterstitialAd': if (!_interstitialReady) return; - _interstitialAd.show(); + _interstitialAd!.show(); _interstitialReady = false; _interstitialAd = null; break; case 'RewardedAd': if (!_rewardedReady) return; - _rewardedAd.show(); + _rewardedAd!.show(); _rewardedReady = false; _rewardedAd = null; break; case 'ReusableInlineExample': Navigator.push( context, - MaterialPageRoute( - builder: (context) => ReusableInlineExample()), + MaterialPageRoute( + builder: (BuildContext context) => + ReusableInlineExample()), ); break; default: - throw AssertionError('unexpected button: ${result}'); + throw AssertionError('unexpected button: $result'); } }, itemBuilder: (BuildContext context) => >[ PopupMenuItem( - child: Text('$InterstitialAd'), value: '$InterstitialAd', + child: Text('$InterstitialAd'), ), PopupMenuItem( - child: Text('$RewardedAd'), value: '$RewardedAd', + child: Text('$RewardedAd'), ), PopupMenuItem( - child: Text('Reusable Inline Ads Object Example'), value: 'ReusableInlineExample', + child: Text('Reusable Inline Ads Object Example'), ), ], ), @@ -224,7 +225,7 @@ class BannerAdWidget extends StatefulWidget { } class BannerAdState extends State { - BannerAd _bannerAd; + late BannerAd _bannerAd; final Completer bannerCompleter = Completer(); @override @@ -242,21 +243,20 @@ class BannerAdState extends State { onAdFailedToLoad: (Ad ad, LoadAdError error) { ad.dispose(); print('$BannerAd failedToLoad: $error'); - bannerCompleter.completeError(null); + bannerCompleter.completeError(error); }, onAdOpened: (Ad ad) => print('$BannerAd onAdOpened.'), onAdClosed: (Ad ad) => print('$BannerAd onAdClosed.'), onApplicationExit: (Ad ad) => print('$BannerAd onApplicationExit.'), ), ); - Future.delayed(Duration(seconds: 1), () => _bannerAd?.load()); + Future.delayed(Duration(seconds: 1), () => _bannerAd.load()); } @override void dispose() { super.dispose(); - _bannerAd?.dispose(); - _bannerAd = null; + _bannerAd.dispose(); } @override @@ -283,8 +283,8 @@ class BannerAdState extends State { return Container( width: _bannerAd.size.width.toDouble(), height: _bannerAd.size.height.toDouble(), - child: child, color: Colors.blueGrey, + child: child, ); }, ); @@ -301,7 +301,7 @@ class PublisherBannerAdWidget extends StatefulWidget { } class PublisherBannerAdState extends State { - PublisherBannerAd _bannerAd; + late PublisherBannerAd _bannerAd; final Completer bannerCompleter = Completer(); @@ -311,7 +311,7 @@ class PublisherBannerAdState extends State { _bannerAd = PublisherBannerAd( adUnitId: '/6499/example/banner', request: PublisherAdRequest(nonPersonalizedAds: true), - sizes: [widget.size], + sizes: [widget.size], listener: AdListener( onAdLoaded: (Ad ad) { print('$PublisherBannerAd loaded.'); @@ -320,7 +320,7 @@ class PublisherBannerAdState extends State { onAdFailedToLoad: (Ad ad, LoadAdError error) { ad.dispose(); print('$PublisherBannerAd failedToLoad: $error'); - bannerCompleter.completeError(null); + bannerCompleter.completeError(error); }, onAdOpened: (Ad ad) => print('$PublisherBannerAd onAdOpened.'), onAdClosed: (Ad ad) => print('$PublisherBannerAd onAdClosed.'), @@ -328,14 +328,13 @@ class PublisherBannerAdState extends State { print('$PublisherBannerAd onApplicationExit.'), ), ); - Future.delayed(Duration(seconds: 1), () => _bannerAd?.load()); + Future.delayed(Duration(seconds: 1), () => _bannerAd.load()); } @override void dispose() { super.dispose(); - _bannerAd?.dispose(); - _bannerAd = null; + _bannerAd.dispose(); } @override @@ -363,8 +362,8 @@ class PublisherBannerAdState extends State { return Container( width: _bannerAd.sizes[0].width.toDouble(), height: _bannerAd.sizes[0].height.toDouble(), - child: child, color: Colors.blueGrey, + child: child, ); }, ); @@ -377,7 +376,7 @@ class NativeAdWidget extends StatefulWidget { } class NativeAdState extends State { - NativeAd _nativeAd; + late NativeAd _nativeAd; final Completer nativeAdCompleter = Completer(); @override @@ -395,21 +394,20 @@ class NativeAdState extends State { onAdFailedToLoad: (Ad ad, LoadAdError error) { ad.dispose(); print('$NativeAd failedToLoad: $error'); - nativeAdCompleter.completeError(null); + nativeAdCompleter.completeError(error); }, onAdOpened: (Ad ad) => print('$NativeAd onAdOpened.'), onAdClosed: (Ad ad) => print('$NativeAd onAdClosed.'), onApplicationExit: (Ad ad) => print('$NativeAd onApplicationExit.'), ), ); - Future.delayed(Duration(seconds: 1), () => _nativeAd?.load()); + Future.delayed(Duration(seconds: 1), () => _nativeAd.load()); } @override void dispose() { super.dispose(); - _nativeAd?.dispose(); - _nativeAd = null; + _nativeAd.dispose(); } @override @@ -436,8 +434,8 @@ class NativeAdState extends State { return Container( width: 250, height: 350, - child: child, color: Colors.blueGrey, + child: child, ); }, ); diff --git a/packages/google_mobile_ads/example/lib/reusable_inline_example.dart b/packages/google_mobile_ads/example/lib/reusable_inline_example.dart index d1e5a9281..aeb17cfdd 100644 --- a/packages/google_mobile_ads/example/lib/reusable_inline_example.dart +++ b/packages/google_mobile_ads/example/lib/reusable_inline_example.dart @@ -13,13 +13,13 @@ class ReusableInlineExample extends StatefulWidget { } class _ReusableInlineExampleState extends State { - BannerAd _bannerAd; + BannerAd? _bannerAd; bool _bannerAdIsLoaded = false; - PublisherBannerAd _publisherBannerAd; + PublisherBannerAd? _publisherBannerAd; bool _publisherBannerAdIsLoaded = false; - NativeAd _nativeAd; + NativeAd? _nativeAd; bool _nativeAdIsLoaded = false; @override @@ -39,23 +39,28 @@ class _ReusableInlineExampleState extends State { ); }, itemBuilder: (BuildContext context, int index) { - if (index == 5 && _bannerAdIsLoaded && _bannerAd != null) { + final BannerAd? bannerAd = _bannerAd; + if (index == 5 && _bannerAdIsLoaded && bannerAd != null) { return Container( - height: _bannerAd.size.height.toDouble(), - width: _bannerAd.size.width.toDouble(), - child: AdWidget(ad: _bannerAd)); + height: bannerAd.size.height.toDouble(), + width: bannerAd.size.width.toDouble(), + child: AdWidget(ad: bannerAd)); } + + final PublisherBannerAd? publisherBannerAd = _publisherBannerAd; if (index == 10 && _publisherBannerAdIsLoaded && - _publisherBannerAd != null) { + publisherBannerAd != null) { return Container( - height: _publisherBannerAd.sizes[0].height.toDouble(), - width: _publisherBannerAd.sizes[0].width.toDouble(), - child: AdWidget(ad: _publisherBannerAd)); + height: publisherBannerAd.sizes[0].height.toDouble(), + width: publisherBannerAd.sizes[0].width.toDouble(), + child: AdWidget(ad: _publisherBannerAd!)); } - if (index == 15 && _nativeAdIsLoaded && _nativeAd != null) { + + final NativeAd? nativeAd = _nativeAd; + if (index == 15 && _nativeAdIsLoaded && nativeAd != null) { return Container( - width: 250, height: 350, child: AdWidget(ad: _nativeAd)); + width: 250, height: 350, child: AdWidget(ad: nativeAd)); } return Text( @@ -81,7 +86,7 @@ class _ReusableInlineExampleState extends State { onAdLoaded: (Ad ad) { print('$BannerAd loaded.'); setState(() { - this._bannerAdIsLoaded = true; + _bannerAdIsLoaded = true; }); }, onAdFailedToLoad: (Ad ad, LoadAdError error) { @@ -105,11 +110,11 @@ class _ReusableInlineExampleState extends State { onAdLoaded: (Ad ad) { print('$NativeAd loaded.'); setState(() { - this._nativeAdIsLoaded = true; + _nativeAdIsLoaded = true; }); }, onAdFailedToLoad: (Ad ad, LoadAdError error) { - print('$NativeAd failedToLoad: ${error}'); + print('$NativeAd failedToLoad: $error'); ad.dispose(); }, onAdOpened: (Ad ad) => print('$NativeAd onAdOpened.'), @@ -121,12 +126,12 @@ class _ReusableInlineExampleState extends State { _publisherBannerAd = PublisherBannerAd( adUnitId: '/6499/example/banner', request: PublisherAdRequest(nonPersonalizedAds: true), - sizes: [AdSize.largeBanner], + sizes: [AdSize.largeBanner], listener: AdListener( onAdLoaded: (Ad ad) { print('$PublisherBannerAd loaded.'); setState(() { - this._publisherBannerAdIsLoaded = true; + _publisherBannerAdIsLoaded = true; }); }, onAdFailedToLoad: (Ad ad, LoadAdError error) { diff --git a/packages/google_mobile_ads/example/pubspec.yaml b/packages/google_mobile_ads/example/pubspec.yaml index 0872122c6..05294bb71 100644 --- a/packages/google_mobile_ads/example/pubspec.yaml +++ b/packages/google_mobile_ads/example/pubspec.yaml @@ -22,8 +22,8 @@ dependencies: path: ../ dev_dependencies: - pedantic: ^1.8.0 - e2e: ^0.2.1 + pedantic: ^1.11.0 + e2e: ^0.7.0 flutter_driver: sdk: flutter @@ -31,4 +31,4 @@ flutter: uses-material-design: true environment: - sdk: ">=2.0.0 <3.0.0" + sdk: ">=2.12.0 <3.0.0" diff --git a/packages/google_mobile_ads/ios/Classes/FLTConstants.h b/packages/google_mobile_ads/ios/Classes/FLTConstants.h index 06d42abf0..7200d9baf 100644 --- a/packages/google_mobile_ads/ios/Classes/FLTConstants.h +++ b/packages/google_mobile_ads/ios/Classes/FLTConstants.h @@ -13,4 +13,4 @@ // limitations under the License. /** Versioned request agent string. */ -#define FLT_REQUEST_AGENT_VERSIONED @"Flutter-GMA-0.11.0+4" +#define FLT_REQUEST_AGENT_VERSIONED @"Flutter-GMA-0.12.0" diff --git a/packages/google_mobile_ads/lib/src/ad_containers.dart b/packages/google_mobile_ads/lib/src/ad_containers.dart index 3e2c70935..1362ec3b2 100644 --- a/packages/google_mobile_ads/lib/src/ad_containers.dart +++ b/packages/google_mobile_ads/lib/src/ad_containers.dart @@ -22,17 +22,13 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; -import 'package:meta/meta.dart'; import 'ad_instance_manager.dart'; /// Error information about why an ad load operation failed. class LoadAdError { /// Default constructor for [LoadAdError]. - LoadAdError(this.code, this.domain, this.message) - : assert(code != null), - assert(domain != null), - assert(message != null); + LoadAdError(this.code, this.domain, this.message); /// Unique code to identify the error. /// @@ -73,32 +69,33 @@ class AdRequest { }); /// Words or phrases describing the current user activity. - final List keywords; + final List? keywords; /// URL string for a webpage whose content matches the app’s primary content. /// /// This webpage content is used for targeting and brand safety purposes. - final String contentUrl; + final String? contentUrl; /// Causes a device to receive test ads. /// /// The deviceId can be obtained by viewing the logcat output after creating a /// new ad. This method should only be used while debugging. Be sure to remove /// all calls to this method before releasing your app. - final List testDevices; + final List? testDevices; /// Non-personalized ads are ads that are not based on a user’s past behavior. /// /// For more information: /// https://support.google.com/admob/answer/7676680?hl=en - final bool nonPersonalizedAds; + final bool? nonPersonalizedAds; @override - bool operator ==(other) { - return this.keywords.toString() == other.keywords.toString() && - this.contentUrl == other.contentUrl && - this.testDevices.toString() == other.testDevices.toString() && - this.nonPersonalizedAds == other.nonPersonalizedAds; + bool operator ==(Object other) { + return other is AdRequest && + listEquals(keywords, other.keywords) && + contentUrl == other.contentUrl && + listEquals(testDevices, other.testDevices) && + nonPersonalizedAds == other.nonPersonalizedAds; } } @@ -114,30 +111,31 @@ class PublisherAdRequest { }); /// Words or phrases describing the current user activity. - final List keywords; + final List? keywords; /// URL string for a webpage whose content matches the app’s primary content. /// /// This webpage content is used for targeting and brand safety purposes. - final String contentUrl; + final String? contentUrl; /// Key-value pairs used for custom targeting. - final Map customTargeting; + final Map? customTargeting; /// Key-value pairs used for custom targeting. - final Map> customTargetingLists; + final Map>? customTargetingLists; /// Non-personalized ads are ads that are not based on a user’s past behavior. /// /// For more information: /// https://support.google.com/admanager/answer/9005435?hl=en - final bool nonPersonalizedAds; + final bool? nonPersonalizedAds; @override - bool operator ==(other) { - return listEquals(keywords, other.keywords) && + bool operator ==(Object other) { + return other is PublisherAdRequest && + listEquals(keywords, other.keywords) && contentUrl == other.contentUrl && - mapEquals(customTargeting, other.customTargeting) && + mapEquals(customTargeting, other.customTargeting) && customTargetingLists.toString() == other.customTargetingLists.toString() && nonPersonalizedAds == other.nonPersonalizedAds; @@ -153,10 +151,9 @@ class PublisherAdRequest { class AdSize { /// Default constructor for [AdSize]. const AdSize({ - @required this.width, - @required this.height, - }) : assert(width != null), - assert(height != null); + required this.width, + required this.height, + }); /// The vertical span of an ad. final int height; @@ -216,8 +213,8 @@ class AdSize { } @override - bool operator ==(other) { - return width == other.width && height == other.height; + bool operator ==(Object other) { + return other is AdSize && width == other.width && height == other.height; } } @@ -237,34 +234,34 @@ class AdListener { }); /// Called when an ad is successfully received. - final void Function(Ad ad) onAdLoaded; + final void Function(Ad ad)? onAdLoaded; /// Called when an ad request failed. - final void Function(Ad ad, LoadAdError error) onAdFailedToLoad; + final void Function(Ad ad, LoadAdError error)? onAdFailedToLoad; /// Called when an app event is received. - final void Function(Ad ad, String name, String data) onAppEvent; + final void Function(Ad ad, String name, String data)? onAppEvent; /// Called when a click is recorded for a [NativeAd]. - final void Function(NativeAd ad) onNativeAdClicked; + final void Function(NativeAd ad)? onNativeAdClicked; /// Called when an impression is recorded for a [NativeAd]. - final void Function(NativeAd ad) onNativeAdImpression; + final void Function(NativeAd ad)? onNativeAdImpression; /// Called when an ad opens an overlay that covers the screen. - final void Function(Ad ad) onAdOpened; + final void Function(Ad ad)? onAdOpened; /// Called when an ad is in the process of leaving the application. - final void Function(Ad ad) onApplicationExit; + final void Function(Ad ad)? onApplicationExit; /// Called when an ad removes an overlay that covers the screen. - final void Function(Ad ad) onAdClosed; + final void Function(Ad ad)? onAdClosed; /// Called when a [RewardedAd] triggers a reward. final void Function( RewardedAd ad, RewardItem reward, - ) onRewardedAdUserEarnedReward; + )? onRewardedAdUserEarnedReward; } /// The base class for all ads. @@ -272,9 +269,7 @@ class AdListener { /// A valid [adUnitId] is required. abstract class Ad { /// Default constructor, used by subclasses. - const Ad({@required this.adUnitId, @required this.listener}) - : assert(adUnitId != null), - assert(listener != null); + const Ad({required this.adUnitId, required this.listener}); /// Receive callbacks from [Ad] lifecycle events. final AdListener listener; @@ -306,15 +301,14 @@ abstract class Ad { /// A valid [adUnitId] and [size] are required. abstract class AdWithView extends Ad { /// Default constructor, used by subclasses. - const AdWithView({@required String adUnitId, @required AdListener listener}) + const AdWithView({required String adUnitId, required AdListener listener}) : super(adUnitId: adUnitId, listener: listener); } /// An [Ad] that is overlaid on top of the UI. abstract class AdWithoutView extends Ad { /// Default constructor used by subclasses. - const AdWithoutView( - {@required String adUnitId, @required AdListener listener}) + const AdWithoutView({required String adUnitId, required AdListener listener}) : super(adUnitId: adUnitId, listener: listener); /// Display this on top of the application. @@ -335,9 +329,7 @@ class AdWidget extends StatefulWidget { /// Default constructor for [AdWidget]. /// /// [ad] must be loaded before this is added to the widget tree. - const AdWidget({Key key, @required this.ad}) - : assert(ad != null), - super(key: key); + const AdWidget({Key? key, required this.ad}) : super(key: key); /// Ad to be displayed as a widget. final AdWithView ad; @@ -348,22 +340,29 @@ class AdWidget extends StatefulWidget { class _AdWidgetState extends State { bool _adIdAlreadyMounted = false; + bool _adLoadNotCalled = false; @override void initState() { super.initState(); - final int adId = instanceManager.adIdFor(widget.ad); - if (instanceManager.isWidgetAdIdMounted(adId)) { - _adIdAlreadyMounted = true; + final int? adId = instanceManager.adIdFor(widget.ad); + if (adId != null) { + if (instanceManager.isWidgetAdIdMounted(adId)) { + _adIdAlreadyMounted = true; + } + instanceManager.mountWidgetAdId(adId); + } else { + _adLoadNotCalled = true; } - instanceManager.mountWidgetAdId(adId); } @override void dispose() { super.dispose(); - final int adId = instanceManager.adIdFor(widget.ad); - instanceManager.unmountWidgetAdId(adId); + final int? adId = instanceManager.adIdFor(widget.ad); + if (adId != null) { + instanceManager.unmountWidgetAdId(adId); + } } @override @@ -378,13 +377,21 @@ class _AdWidgetState extends State { 'Make sure you are not using the same ad object in more than one AdWidget.'), ]); } + if (_adLoadNotCalled) { + throw FlutterError.fromParts([ + ErrorSummary( + 'AdWidget requires Ad.load to be called before AdWidget is inserted into the tree'), + ErrorHint( + 'Parameter ad is not loaded. Call Ad.load before AdWidget is inserted into the tree.'), + ]); + } if (defaultTargetPlatform == TargetPlatform.android) { return PlatformViewLink( viewType: '${instanceManager.channel.name}/ad_widget', surfaceFactory: (BuildContext context, PlatformViewController controller) { return AndroidViewSurface( - controller: controller, + controller: controller as AndroidViewController, gestureRecognizers: const >{}, hitTestBehavior: PlatformViewHitTestBehavior.opaque, ); @@ -421,13 +428,11 @@ class BannerAd extends AdWithView { /// /// A valid [adUnitId], nonnull [listener], and nonnull request is required. BannerAd({ - @required this.size, - @required String adUnitId, - @required AdListener listener, - @required this.request, - }) : assert(size != null), - assert(request != null), - super(adUnitId: adUnitId, listener: listener); + required this.size, + required String adUnitId, + required AdListener listener, + required this.request, + }) : super(adUnitId: adUnitId, listener: listener); /// Targeting information used to fetch an [Ad]. final AdRequest request; @@ -465,13 +470,11 @@ class PublisherBannerAd extends AdWithView { /// /// [sizes], [adUnitId], [listener], and [request] are all required values. PublisherBannerAd({ - @required this.sizes, - @required String adUnitId, - @required AdListener listener, - @required this.request, - }) : assert(sizes != null), - assert(sizes.isNotEmpty), - assert(request != null), + required this.sizes, + required String adUnitId, + required AdListener listener, + required this.request, + }) : assert(sizes.isNotEmpty), super(adUnitId: adUnitId, listener: listener); /// Targeting information used to fetch an [Ad]. @@ -517,15 +520,12 @@ class NativeAd extends AdWithView { /// A valid [adUnitId], nonnull [listener], nonnull [request], and nonnull /// [factoryId] is required. NativeAd({ - @required String adUnitId, - @required this.factoryId, - @required AdListener listener, - @required this.request, + required String adUnitId, + required this.factoryId, + required AdListener listener, + required this.request, this.customOptions, }) : publisherRequest = null, - assert(adUnitId != null), - assert(listener != null), - assert(factoryId != null), assert(request != null), super(adUnitId: adUnitId, listener: listener); @@ -534,15 +534,12 @@ class NativeAd extends AdWithView { /// A valid [adUnitId], nonnull [listener], nonnull [publisherRequest], and /// nonnull [factoryId] is required. NativeAd.fromPublisherRequest({ - @required String adUnitId, - @required this.factoryId, - @required AdListener listener, - @required this.publisherRequest, + required String adUnitId, + required this.factoryId, + required AdListener listener, + required this.publisherRequest, this.customOptions, }) : request = null, - assert(factoryId != null), - assert(adUnitId != null), - assert(listener != null), assert(publisherRequest != null), super(adUnitId: adUnitId, listener: listener); @@ -552,13 +549,13 @@ class NativeAd extends AdWithView { /// Optional options used to create the [NativeAd]. /// /// These options are passed to the platform's `NativeAdFactory`. - Map customOptions; + Map? customOptions; /// Targeting information used to fetch an [Ad]. - final AdRequest request; + final AdRequest? request; /// Targeting information used to fetch an [Ad] with Ad Manager. - final PublisherAdRequest publisherRequest; + final PublisherAdRequest? publisherRequest; /// {@template google_mobile_ads.testAdUnitId} /// A platform-specific AdMob test ad unit ID. @@ -584,11 +581,10 @@ class InterstitialAd extends AdWithoutView { /// A valid [adUnitId] from the AdMob dashboard, a nonnull [listener], and a /// nonnull [request] is required. InterstitialAd({ - @required String adUnitId, - @required AdListener listener, - @required this.request, - }) : assert(request != null), - super(adUnitId: adUnitId, listener: listener); + required String adUnitId, + required AdListener listener, + required this.request, + }) : super(adUnitId: adUnitId, listener: listener); /// Targeting information used to fetch an [Ad]. final AdRequest request; @@ -611,11 +607,10 @@ class PublisherInterstitialAd extends AdWithoutView { /// A valid [adUnitId] from the Ad Manager dashboard, a nonnull [listener], /// and nonnull [request] is required. PublisherInterstitialAd({ - @required String adUnitId, - @required AdListener listener, - @required this.request, - }) : assert(request != null), - super(adUnitId: adUnitId, listener: listener); + required String adUnitId, + required AdListener listener, + required this.request, + }) : super(adUnitId: adUnitId, listener: listener); /// Targeting information used to fetch an [Ad]. final PublisherAdRequest request; @@ -635,27 +630,27 @@ class RewardedAd extends AdWithoutView { /// /// A valid [adUnitId], nonnull [listener], and nonnull request is required. RewardedAd({ - @required String adUnitId, - @required AdListener listener, - @required this.request, - }) : publisherRequest = null, + required String adUnitId, + required AdListener listener, + required this.request, + }) : publisherRequest = null, super(adUnitId: adUnitId, listener: listener); /// Creates a [RewardedAd] with a [PublisherAdRequest]. /// /// A valid [adUnitId], nonnull [listener], and nonnull request is required. RewardedAd.fromPublisherRequest({ - @required String adUnitId, - @required AdListener listener, - @required this.publisherRequest, - }) : request = null, + required String adUnitId, + required AdListener listener, + required this.publisherRequest, + }) : request = null, super(adUnitId: adUnitId, listener: listener); /// Targeting information used to fetch an [Ad]. - final AdRequest request; + final AdRequest? request; /// Targeting information used to fetch an [Ad] using Ad Manager. - final PublisherAdRequest publisherRequest; + final PublisherAdRequest? publisherRequest; /// {@template google_mobile_ads.testAdUnitId} /// A platform-specific AdMob test ad unit ID. @@ -680,9 +675,7 @@ class RewardItem { /// /// This is mostly used to return [RewardItem]s for a [RewardedAd] and /// shouldn't be needed to be used directly. - RewardItem(this.amount, this.type) - : assert(amount != null), - assert(type != null); + RewardItem(this.amount, this.type); /// Credit amount rewarded from a [RewardedAd]. final num amount; diff --git a/packages/google_mobile_ads/lib/src/ad_instance_manager.dart b/packages/google_mobile_ads/lib/src/ad_instance_manager.dart index 055ef7fdf..5d0b62162 100644 --- a/packages/google_mobile_ads/lib/src/ad_instance_manager.dart +++ b/packages/google_mobile_ads/lib/src/ad_instance_manager.dart @@ -35,8 +35,7 @@ AdInstanceManager instanceManager = AdInstanceManager( /// Maintains access to loaded [Ad] instances. class AdInstanceManager { AdInstanceManager(String channelName) - : assert(channelName != null), - channel = MethodChannel( + : channel = MethodChannel( channelName, StandardMethodCodec(AdMessageCodec()), ) { @@ -46,7 +45,7 @@ class AdInstanceManager { final int adId = call.arguments['adId']; final String eventName = call.arguments['eventName']; - final Ad ad = adFor(adId); + final Ad? ad = adFor(adId); if (ad != null) { _onAdEvent(ad, eventName, call.arguments); } else { @@ -65,36 +64,36 @@ class AdInstanceManager { final MethodChannel channel; void _onAdEvent(Ad ad, String eventName, Map arguments) { - assert(ad != null); switch (eventName) { case 'onAdLoaded': _onAdLoadedAds.add(ad); - ad.listener?.onAdLoaded(ad); + ad.listener.onAdLoaded?.call(ad); break; case 'onAdFailedToLoad': - ad.listener?.onAdFailedToLoad(ad, arguments['loadAdError']); + ad.listener.onAdFailedToLoad?.call(ad, arguments['loadAdError']); break; case 'onNativeAdClicked': - ad.listener?.onNativeAdClicked(ad); + ad.listener.onNativeAdClicked?.call(ad as NativeAd); break; case 'onNativeAdImpression': - ad.listener?.onNativeAdImpression(ad); + ad.listener.onNativeAdImpression?.call(ad as NativeAd); break; case 'onAdOpened': - ad.listener?.onAdOpened(ad); + ad.listener.onAdOpened?.call(ad); break; case 'onApplicationExit': - ad.listener?.onApplicationExit(ad); + ad.listener.onApplicationExit?.call(ad); break; case 'onAdClosed': - ad.listener?.onAdClosed(ad); + ad.listener.onAdClosed?.call(ad); break; case 'onAppEvent': - ad.listener?.onAppEvent(ad, arguments['name'], arguments['data']); + ad.listener.onAppEvent?.call(ad, arguments['name'], arguments['data']); break; case 'onRewardedAdUserEarnedReward': assert(arguments['rewardItem'] != null); - ad.listener?.onRewardedAdUserEarnedReward(ad, arguments['rewardItem']); + ad.listener.onRewardedAdUserEarnedReward + ?.call(ad as RewardedAd, arguments['rewardItem']); break; default: debugPrint('invalid ad event name: $eventName'); @@ -102,12 +101,12 @@ class AdInstanceManager { } /// Returns null if an invalid [adId] was passed in. - Ad adFor(int adId) => _loadedAds[adId]; + Ad? adFor(int adId) => _loadedAds[adId]; /// Returns null if an invalid [Ad] was passed in. - int adIdFor(Ad ad) => _loadedAds.inverse[ad]; + int? adIdFor(Ad ad) => _loadedAds.inverse[ad]; - Set _mountedWidgetAdIds = {}; + final Set _mountedWidgetAdIds = {}; /// Returns true if the [adId] is already mounted in a [WidgetAd]. bool isWidgetAdIdMounted(int adId) => _mountedWidgetAdIds.contains(adId); @@ -123,17 +122,16 @@ class AdInstanceManager { /// Loading also terminates if ad is already in the process of loading. Future loadBannerAd(BannerAd ad) { if (adIdFor(ad) != null) { - return null; + return Future.value(); } final int adId = _nextAdId++; _loadedAds[adId] = ad; - final Ad bannerAd = adFor(adId); return channel.invokeMethod( 'loadBannerAd', { 'adId': adId, - 'adUnitId': bannerAd.adUnitId, + 'adUnitId': ad.adUnitId, 'request': ad.request, 'size': ad.size, }, @@ -142,18 +140,17 @@ class AdInstanceManager { Future loadInterstitialAd(InterstitialAd ad) { if (adIdFor(ad) != null) { - return null; + return Future.value(); } final int adId = _nextAdId++; _loadedAds[adId] = ad; - final InterstitialAd interstitialAd = adFor(adId); return channel.invokeMethod( 'loadInterstitialAd', { 'adId': adId, - 'adUnitId': interstitialAd.adUnitId, - 'request': interstitialAd.request, + 'adUnitId': ad.adUnitId, + 'request': ad.request, }, ); } @@ -163,17 +160,16 @@ class AdInstanceManager { /// Loading also terminates if ad is already in the process of loading. Future loadNativeAd(NativeAd ad) { if (adIdFor(ad) != null) { - return null; + return Future.value(); } final int adId = _nextAdId++; _loadedAds[adId] = ad; - final Ad nativeAd = adFor(adId); return channel.invokeMethod( 'loadNativeAd', { 'adId': adId, - 'adUnitId': nativeAd.adUnitId, + 'adUnitId': ad.adUnitId, 'request': ad.request, 'publisherRequest': ad.publisherRequest, 'factoryId': ad.factoryId, @@ -187,19 +183,18 @@ class AdInstanceManager { /// Loading also terminates if ad is already in the process of loading. Future loadRewardedAd(RewardedAd ad) { if (adIdFor(ad) != null) { - return null; + return Future.value(); } final int adId = _nextAdId++; _loadedAds[adId] = ad; - final RewardedAd rewardedAd = adFor(adId); return channel.invokeMethod( 'loadRewardedAd', { 'adId': adId, - 'adUnitId': rewardedAd.adUnitId, - 'request': rewardedAd.request, - 'publisherRequest': rewardedAd.publisherRequest, + 'adUnitId': ad.adUnitId, + 'request': ad.request, + 'publisherRequest': ad.publisherRequest, }, ); } @@ -209,7 +204,7 @@ class AdInstanceManager { /// Loading also terminates if ad is already in the process of loading. Future loadPublisherBannerAd(PublisherBannerAd ad) { if (adIdFor(ad) != null) { - return null; + return Future.value(); } final int adId = _nextAdId++; @@ -230,7 +225,7 @@ class AdInstanceManager { /// Loading also terminates if ad is already in the process of loading. Future loadPublisherInterstitialAd(PublisherInterstitialAd ad) { if (adIdFor(ad) != null) { - return null; + return Future.value(); } final int adId = _nextAdId++; @@ -252,10 +247,10 @@ class AdInstanceManager { Future disposeAd(Ad ad) { _onAdLoadedAds.remove(ad); - final int adId = adIdFor(ad); - final Ad disposedAd = _loadedAds.remove(adId); + final int? adId = adIdFor(ad); + final Ad? disposedAd = _loadedAds.remove(adId); if (disposedAd == null) { - return null; + return Future.value(); } return channel.invokeMethod( 'disposeAd', @@ -386,7 +381,7 @@ class AdMessageCodec extends StandardMessageCodec { contentUrl: readValueOfType(buffer.getUint8(), buffer), customTargeting: readValueOfType(buffer.getUint8(), buffer) ?.cast(), - customTargetingLists: _deepMapCast( + customTargetingLists: _tryDeepMapCast( readValueOfType(buffer.getUint8(), buffer), ), nonPersonalizedAds: readValueOfType(buffer.getUint8(), buffer), @@ -404,11 +399,10 @@ class AdMessageCodec extends StandardMessageCodec { readValueOfType(buffer.getUint8(), buffer); final String description = readValueOfType(buffer.getUint8(), buffer); - double latency = readValueOfType(buffer.getUint8(), buffer)?.toDouble(); + double latency = readValueOfType(buffer.getUint8(), buffer).toDouble(); // Android provides this value as an int in milliseconds while iOS // provides this value as a double in seconds. - if (latency != null && - defaultTargetPlatform == TargetPlatform.android) { + if (defaultTargetPlatform == TargetPlatform.android) { latency /= 1000; } @@ -423,7 +417,7 @@ class AdMessageCodec extends StandardMessageCodec { } } - Map> _deepMapCast(Map map) { + Map>? _tryDeepMapCast(Map? map) { if (map == null) return null; return map.map>( (dynamic key, dynamic value) => MapEntry>( @@ -442,12 +436,12 @@ class _BiMap extends MapBase { _BiMap._inverse(this._inverse); final Map _map = {}; - _BiMap _inverse; + late _BiMap _inverse; - _BiMap get inverse => _inverse; + _BiMap get inverse => _inverse; @override - V operator [](Object key) => _map[key]; + V? operator [](Object? key) => _map[key]; @override void operator []=(K key, V value) { @@ -467,9 +461,9 @@ class _BiMap extends MapBase { Iterable get keys => _map.keys; @override - V remove(Object key) { + V? remove(Object? key) { if (key == null) return null; - final V value = _map[key]; + final V? value = _map[key]; inverse._map.remove(value); return _map.remove(key); } diff --git a/packages/google_mobile_ads/lib/src/mobile_ads.dart b/packages/google_mobile_ads/lib/src/mobile_ads.dart index 3828f3e21..c5dfbf7c8 100644 --- a/packages/google_mobile_ads/lib/src/mobile_ads.dart +++ b/packages/google_mobile_ads/lib/src/mobile_ads.dart @@ -44,10 +44,10 @@ class MobileAds { /// /// If this method is not called, the first ad request automatically /// initializes the Google Mobile Ads SDK. - Future initialize() { - return instanceManager.channel.invokeMethod( + Future initialize() async { + return (await instanceManager.channel.invokeMethod( 'MobileAds#initialize', - ); + ))!; } /// Update the [RequestConfiguration] to apply for future ad requests. @@ -59,7 +59,7 @@ class MobileAds { /// Internal init to cleanup state for hot restart. /// This is a workaround for https://github.com/flutter/flutter/issues/7160. void _init() { - instanceManager.channel.invokeMethod("_init"); + instanceManager.channel.invokeMethod('_init'); } } diff --git a/packages/google_mobile_ads/lib/src/request_configuration.dart b/packages/google_mobile_ads/lib/src/request_configuration.dart index feec75cc5..e027b5c1a 100644 --- a/packages/google_mobile_ads/lib/src/request_configuration.dart +++ b/packages/google_mobile_ads/lib/src/request_configuration.dart @@ -18,16 +18,16 @@ /// https://developers.google.com/ad-manager/mobile-ads-sdk/android/targeting#requestconfiguration. class RequestConfiguration { /// Maximum content rating that will be shown. - final String maxAdContentRating; + final String? maxAdContentRating; /// Whether to tag as child directed. - final int tagForChildDirectedTreatment; + final int? tagForChildDirectedTreatment; /// Whether to tag as under age of consent. - final int tagForUnderAgeOfConsent; + final int? tagForUnderAgeOfConsent; /// List of test device ids to set. - final List testDeviceIds; + final List? testDeviceIds; /// Creates a [RequestConfiguration]. RequestConfiguration( @@ -40,19 +40,19 @@ class RequestConfiguration { /// Values for [RequestConfiguration.maxAdContentRating]. class MaxAdContentRating { /// No specified content rating. - static final String unspecified = ""; + static final String unspecified = ''; /// Content suitable for general audiences, including families. - static final String g = "G"; + static final String g = 'G'; /// Content suitable for most audiences with parental guidance. - static final String pg = "PG"; + static final String pg = 'PG'; /// Content suitable for most audiences with parental guidance. - static final String t = "T"; + static final String t = 'T'; /// Content suitable only for mature audiences. - static final String ma = "MA"; + static final String ma = 'MA'; } /// Values for [RequestConfiguration.tagForUnderAgeOfConsent]. diff --git a/packages/google_mobile_ads/pubspec.yaml b/packages/google_mobile_ads/pubspec.yaml index ddfe59889..27db6bf96 100644 --- a/packages/google_mobile_ads/pubspec.yaml +++ b/packages/google_mobile_ads/pubspec.yaml @@ -16,7 +16,7 @@ name: google_mobile_ads description: Flutter plugin for Google Mobile Ads, supporting banner, interstitial (full-screen), rewarded and native ads homepage: https://github.com/googleads/googleads-mobile-flutter/tree/master/packages/google_mobile_ads -version: 0.11.0+4 +version: 0.12.0 flutter: plugin: @@ -33,14 +33,14 @@ dependencies: sdk: flutter dev_dependencies: - pedantic: ^1.8.0 - e2e: ^0.2.1 + pedantic: ^1.11.0 + e2e: ^0.7.0 flutter_driver: sdk: flutter - mockito: ^3.0.0 + mockito: ^5.0.0-0 flutter_test: sdk: flutter environment: - sdk: ">=2.7.0 <3.0.0" + sdk: ">=2.12.0 <3.0.0" flutter: ">=1.12.13+hotfix.5" diff --git a/packages/google_mobile_ads/test/ad_containers_test.dart b/packages/google_mobile_ads/test/ad_containers_test.dart index 8be9852e0..a9bb4961d 100644 --- a/packages/google_mobile_ads/test/ad_containers_test.dart +++ b/packages/google_mobile_ads/test/ad_containers_test.dart @@ -12,8 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -// @dart=2.9 - import 'dart:async'; import 'package:google_mobile_ads/src/ad_instance_manager.dart'; @@ -27,7 +25,7 @@ void main() { group('GoogleMobileAds', () { final List log = []; - final MessageCodec codec = AdMessageCodec(); + final MessageCodec codec = AdMessageCodec(); setUp(() async { log.clear(); @@ -58,7 +56,7 @@ void main() { maxAdContentRating: MaxAdContentRating.ma, tagForChildDirectedTreatment: TagForChildDirectedTreatment.yes, tagForUnderAgeOfConsent: TagForUnderAgeOfConsent.yes, - testDeviceIds: ["test-device-id"], + testDeviceIds: ['test-device-id'], ); await instanceManager.updateRequestConfiguration(requestConfiguration); expect(log, [ @@ -67,7 +65,7 @@ void main() { 'maxAdContentRating': MaxAdContentRating.ma, 'tagForChildDirectedTreatment': TagForChildDirectedTreatment.yes, 'tagForUnderAgeOfConsent': TagForUnderAgeOfConsent.yes, - 'testDeviceIds': ['test-device-id'], + 'testDeviceIds': ['test-device-id'], }) ]); }); @@ -181,43 +179,88 @@ void main() { }); testWidgets('build ad widget', (WidgetTester tester) async { + final NativeAd native = NativeAd( + adUnitId: NativeAd.testAdUnitId, + factoryId: '0', + listener: AdListener(), + request: AdRequest(), + ); + + await native.load(); + await tester.pumpWidget( Builder( builder: (BuildContext context) { - final NativeAd native = NativeAd( - adUnitId: NativeAd.testAdUnitId, - factoryId: '0', - listener: AdListener(), - request: AdRequest(), - ); - AdWidget widget = AdWidget(ad: native); - var buildWidget = widget.createElement().build(); + Widget buildWidget = widget.createElement().build(); expect(buildWidget, isA()); return widget; }, ), ); + + await native.dispose(); }); testWidgets('build ad widget', (WidgetTester tester) async { + final NativeAd native = NativeAd( + adUnitId: NativeAd.testAdUnitId, + factoryId: '0', + listener: AdListener(), + request: AdRequest(), + ); + + await native.load(); + await tester.pumpWidget( Builder( builder: (BuildContext context) { - final NativeAd native = NativeAd( - adUnitId: NativeAd.testAdUnitId, - factoryId: '0', - listener: AdListener(), - request: AdRequest(), - ); - AdWidget widget = AdWidget(ad: native); - var buildWidget = widget.createElement().build(); + Widget buildWidget = widget.createElement().build(); expect(buildWidget, isA()); return widget; }, ), ); + + await native.dispose(); + }); + + testWidgets('warns when ad has not been loaded', + (WidgetTester tester) async { + final NativeAd ad = NativeAd( + adUnitId: NativeAd.testAdUnitId, + factoryId: '0', + listener: AdListener(), + request: AdRequest(), + ); + + try { + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: SizedBox( + width: 100, + height: 100, + child: Stack( + children: [ + AdWidget(ad: ad), + ], + ), + ), + ), + ); + } finally { + dynamic exception = tester.takeException(); + expect(exception, isA()); + expect( + (exception as FlutterError).toStringDeep(), + 'FlutterError\n' + ' AdWidget requires Ad.load to be called before AdWidget is\n' + ' inserted into the tree\n' + ' Parameter ad is not loaded. Call Ad.load before AdWidget is\n' + ' inserted into the tree.\n'); + } }); testWidgets('warns when ad object is reused', (WidgetTester tester) async { @@ -451,7 +494,7 @@ void main() { await instanceManager.channel.binaryMessenger.handlePlatformMessage( 'plugins.flutter.io/google_mobile_ads', data, - (ByteData data) {}, + (ByteData? data) {}, ); expect(adEventCompleter.future, completion(banner)); @@ -484,7 +527,7 @@ void main() { await instanceManager.channel.binaryMessenger.handlePlatformMessage( 'plugins.flutter.io/google_mobile_ads', data, - (ByteData data) {}, + (ByteData? data) {}, ); final List results = await resultsCompleter.future; @@ -516,7 +559,7 @@ void main() { await instanceManager.channel.binaryMessenger.handlePlatformMessage( 'plugins.flutter.io/google_mobile_ads', data, - (ByteData data) {}, + (ByteData? data) {}, ); expect(adEventCompleter.future, completion(native)); @@ -544,7 +587,7 @@ void main() { await instanceManager.channel.binaryMessenger.handlePlatformMessage( 'plugins.flutter.io/google_mobile_ads', data, - (ByteData data) {}, + (ByteData? data) {}, ); expect(adEventCompleter.future, completion(native)); @@ -572,7 +615,7 @@ void main() { await instanceManager.channel.binaryMessenger.handlePlatformMessage( 'plugins.flutter.io/google_mobile_ads', data, - (ByteData data) {}, + (ByteData? data) {}, ); expect(adEventCompleter.future, completion(banner)); @@ -600,7 +643,7 @@ void main() { await instanceManager.channel.binaryMessenger.handlePlatformMessage( 'plugins.flutter.io/google_mobile_ads', data, - (ByteData data) {}, + (ByteData? data) {}, ); expect(adEventCompleter.future, completion(banner)); @@ -628,7 +671,7 @@ void main() { await instanceManager.channel.binaryMessenger.handlePlatformMessage( 'plugins.flutter.io/google_mobile_ads', data, - (ByteData data) {}, + (ByteData? data) {}, ); expect(adEventCompleter.future, completion(banner)); @@ -661,7 +704,7 @@ void main() { await instanceManager.channel.binaryMessenger.handlePlatformMessage( 'plugins.flutter.io/google_mobile_ads', data, - (ByteData data) {}, + (ByteData? data) {}, ); final List result = await resultCompleter.future; @@ -698,25 +741,25 @@ void main() { }); test('encode/decode AdSize', () async { - final ByteData byteData = codec.encodeMessage(AdSize.banner); + final ByteData byteData = codec.encodeMessage(AdSize.banner)!; expect(codec.decodeMessage(byteData), AdSize.banner); }); test('encode/decode AdRequest', () async { final AdRequest adRequest = AdRequest( - keywords: ['1', '2', '3'], + keywords: ['1', '2', '3'], contentUrl: 'contentUrl', - testDevices: ['Android', 'iOS'], + testDevices: ['Android', 'iOS'], nonPersonalizedAds: false); - final ByteData byteData = codec.encodeMessage(adRequest); + final ByteData byteData = codec.encodeMessage(adRequest)!; expect(codec.decodeMessage(byteData), adRequest); }); test('encode/decode $LoadAdError', () async { final ByteData byteData = codec.encodeMessage( LoadAdError(1, 'domain', 'message'), - ); + )!; final LoadAdError error = codec.decodeMessage(byteData); expect(error.code, 1); expect(error.domain, 'domain'); @@ -724,7 +767,7 @@ void main() { }); test('encode/decode $RewardItem', () async { - final ByteData byteData = codec.encodeMessage(RewardItem(1, 'type')); + final ByteData byteData = codec.encodeMessage(RewardItem(1, 'type'))!; final RewardItem result = codec.decodeMessage(byteData); expect(result.amount, 1); @@ -740,7 +783,7 @@ void main() { 'him': ['is'] }, nonPersonalizedAds: true, - )); + ))!; expect( codec.decodeMessage(byteData), @@ -783,7 +826,7 @@ void main() { await instanceManager.channel.binaryMessenger.handlePlatformMessage( 'plugins.flutter.io/google_mobile_ads', data, - (ByteData data) {}, + (ByteData? data) {}, ); expect(banner.isLoaded(), completion(true)); diff --git a/packages/google_mobile_ads/test/mobile_ads_test.dart b/packages/google_mobile_ads/test/mobile_ads_test.dart index 3afb15b96..ca7636e5f 100644 --- a/packages/google_mobile_ads/test/mobile_ads_test.dart +++ b/packages/google_mobile_ads/test/mobile_ads_test.dart @@ -42,7 +42,7 @@ void main() { 'aName': AdapterStatus( AdapterInitializationState.notReady, 'desc', - null, + 0, ), }); case '_init': @@ -56,7 +56,7 @@ void main() { test('encode/decode $AdapterInitializationState', () { final ByteData byteData = - codec.encodeMessage(AdapterInitializationState.ready); + codec.encodeMessage(AdapterInitializationState.ready)!; final AdapterInitializationState result = codec.decodeMessage(byteData); expect(result, AdapterInitializationState.ready); @@ -68,7 +68,7 @@ void main() { AdapterInitializationState.notReady, 'describe', 23, - )); + ))!; AdapterStatus result = codec.decodeMessage(byteData); expect(result.state, AdapterInitializationState.notReady); @@ -85,7 +85,7 @@ void main() { test('handle int values for AdapterStatus', () { final WriteBuffer buffer = WriteBuffer(); codec.writeValue(buffer, AdapterInitializationState.ready); - codec.writeValue(buffer, null); + codec.writeValue(buffer, 'aDescription'); codec.writeValue(buffer, 23); expect( @@ -103,31 +103,31 @@ void main() { 'adMediation': AdapterStatus( AdapterInitializationState.ready, 'aDescription', - null, + 0, ), - })); + }))!; final InitializationStatus result = codec.decodeMessage(byteData); expect(result.adapterStatuses, hasLength(1)); - final AdapterStatus status = result.adapterStatuses['adMediation']; + final AdapterStatus status = result.adapterStatuses['adMediation']!; expect(status.state, AdapterInitializationState.ready); expect(status.description, 'aDescription'); - expect(status.latency, null); + expect(status.latency, 0); }); test('$MobileAds.initialize', () async { final InitializationStatus result = await MobileAds.instance.initialize(); expect(log, [ - isMethodCall("_init", arguments: null), - isMethodCall("MobileAds#initialize", arguments: null) + isMethodCall('_init', arguments: null), + isMethodCall('MobileAds#initialize', arguments: null) ]); expect(result.adapterStatuses, hasLength(1)); - final AdapterStatus status = result.adapterStatuses['aName']; + final AdapterStatus status = result.adapterStatuses['aName']!; expect(status.state, AdapterInitializationState.notReady); expect(status.description, 'desc'); - expect(status.latency, null); + expect(status.latency, 0); }); }); }