|  | // ignore_for_file: deprecated_member_use | 
|  | // Copyright 2017 The Chromium 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 'dart:io' show Platform; | 
|  |  | 
|  | import 'package:flutter/services.dart'; | 
|  | import 'package:meta/meta.dart'; | 
|  |  | 
|  | /// [MobileAd] status changes reported to [MobileAdListener]s. | 
|  | /// | 
|  | /// Applications can wait until an ad is [MobileAdEvent.loaded] before showing | 
|  | /// it, to ensure that the ad is displayed promptly. | 
|  | enum MobileAdEvent { | 
|  | loaded, | 
|  | failedToLoad, | 
|  | clicked, | 
|  | impression, | 
|  | opened, | 
|  | leftApplication, | 
|  | closed, | 
|  | } | 
|  |  | 
|  | /// The user's gender for the sake of ad targeting using [MobileAdTargetingInfo]. | 
|  | // Warning: the index values of the enums must match the values of the corresponding | 
|  | // AdMob constants. For example MobileAdGender.female.index == kGADGenderFemale. | 
|  | @Deprecated('This functionality is deprecated in AdMob without replacement.') | 
|  | enum MobileAdGender { | 
|  | unknown, | 
|  | male, | 
|  | female, | 
|  | } | 
|  |  | 
|  | /// Signature for a [MobileAd] status change callback. | 
|  | typedef void MobileAdListener(MobileAdEvent event); | 
|  |  | 
|  | /// Targeting info per the native AdMob API. | 
|  | /// | 
|  | /// This class's properties mirror the native AdRequest API. See for example: | 
|  | /// [AdRequest.Builder for Android](https://firebase.google.com/docs/reference/android/com/google/android/gms/ads/AdRequest.Builder). | 
|  | class MobileAdTargetingInfo { | 
|  | const MobileAdTargetingInfo( | 
|  | {this.keywords, | 
|  | this.contentUrl, | 
|  | @Deprecated('This functionality is deprecated in AdMob without replacement.') | 
|  | this.birthday, | 
|  | @Deprecated('This functionality is deprecated in AdMob without replacement.') | 
|  | this.gender, | 
|  | @Deprecated('Use `childDirected` instead.') | 
|  | this.designedForFamilies, | 
|  | this.childDirected, | 
|  | this.testDevices, | 
|  | this.nonPersonalizedAds}); | 
|  |  | 
|  | final List<String> keywords; | 
|  | final String contentUrl; | 
|  | @Deprecated('This functionality is deprecated in AdMob without replacement.') | 
|  | final DateTime birthday; | 
|  | @Deprecated('This functionality is deprecated in AdMob without replacement.') | 
|  | final MobileAdGender gender; | 
|  | @Deprecated( | 
|  | 'This functionality is deprecated in AdMob.  Use `childDirected` instead.') | 
|  | final bool designedForFamilies; | 
|  | final bool childDirected; | 
|  | final List<String> testDevices; | 
|  | final bool nonPersonalizedAds; | 
|  |  | 
|  | Map<String, dynamic> toJson() { | 
|  | final Map<String, dynamic> json = <String, dynamic>{ | 
|  | 'requestAgent': 'flutter-alpha', | 
|  | }; | 
|  |  | 
|  | if (keywords != null && keywords.isNotEmpty) { | 
|  | assert(keywords.every((String s) => s != null && s.isNotEmpty)); | 
|  | json['keywords'] = keywords; | 
|  | } | 
|  | if (nonPersonalizedAds != null) | 
|  | json['nonPersonalizedAds'] = nonPersonalizedAds; | 
|  | if (contentUrl != null && contentUrl.isNotEmpty) | 
|  | json['contentUrl'] = contentUrl; | 
|  | if (birthday != null) json['birthday'] = birthday.millisecondsSinceEpoch; | 
|  | if (gender != null) json['gender'] = gender.index; | 
|  | if (designedForFamilies != null) | 
|  | json['designedForFamilies'] = designedForFamilies; | 
|  | if (childDirected != null) json['childDirected'] = childDirected; | 
|  | if (testDevices != null && testDevices.isNotEmpty) { | 
|  | assert(testDevices.every((String s) => s != null && s.isNotEmpty)); | 
|  | json['testDevices'] = testDevices; | 
|  | } | 
|  |  | 
|  | return json; | 
|  | } | 
|  | } | 
|  |  | 
|  | enum AnchorType { bottom, top } | 
|  |  | 
|  | // The types of ad sizes supported for banners. The names of the values are used | 
|  | // in MethodChannel calls to iOS and Android, and should not be changed. | 
|  | enum AdSizeType { | 
|  | WidthAndHeight, | 
|  | SmartBanner, | 
|  | } | 
|  |  | 
|  | /// [AdSize] represents the size of a banner ad. There are six sizes available, | 
|  | /// which are the same for both iOS and Android. See the guides for banners on | 
|  | /// [Android](https://developers.google.com/admob/android/banner#banner_sizes) | 
|  | /// and [iOS](https://developers.google.com/admob/ios/banner#banner_sizes) for | 
|  | /// additional details. | 
|  | class AdSize { | 
|  | // Private constructor. Apps should use the static constants rather than | 
|  | // create their own instances of [AdSize]. | 
|  | const AdSize._({ | 
|  | @required this.width, | 
|  | @required this.height, | 
|  | @required this.adSizeType, | 
|  | }); | 
|  |  | 
|  | final int height; | 
|  | final int width; | 
|  | final AdSizeType adSizeType; | 
|  |  | 
|  | /// The standard banner (320x50) size. | 
|  | static const AdSize banner = AdSize._( | 
|  | width: 320, | 
|  | height: 50, | 
|  | adSizeType: AdSizeType.WidthAndHeight, | 
|  | ); | 
|  |  | 
|  | /// The large banner (320x100) size. | 
|  | static const AdSize largeBanner = AdSize._( | 
|  | width: 320, | 
|  | height: 100, | 
|  | adSizeType: AdSizeType.WidthAndHeight, | 
|  | ); | 
|  |  | 
|  | /// The medium rectangle (300x250) size. | 
|  | static const AdSize mediumRectangle = AdSize._( | 
|  | width: 300, | 
|  | height: 250, | 
|  | adSizeType: AdSizeType.WidthAndHeight, | 
|  | ); | 
|  |  | 
|  | /// The full banner (468x60) size. | 
|  | static const AdSize fullBanner = AdSize._( | 
|  | width: 468, | 
|  | height: 60, | 
|  | adSizeType: AdSizeType.WidthAndHeight, | 
|  | ); | 
|  |  | 
|  | /// The leaderboard (728x90) size. | 
|  | static const AdSize leaderboard = AdSize._( | 
|  | width: 728, | 
|  | height: 90, | 
|  | adSizeType: AdSizeType.WidthAndHeight, | 
|  | ); | 
|  |  | 
|  | /// The smart banner size. Smart banners are unique in that the width and | 
|  | /// height values declared here aren't used. At runtime, the Mobile Ads SDK | 
|  | /// will automatically adjust the banner's width to match the width of the | 
|  | /// displaying device's screen. It will also set the banner's height using a | 
|  | /// calculation based on the displaying device's height. For more info see the | 
|  | /// [Android](https://developers.google.com/admob/android/banner) and | 
|  | /// [iOS](https://developers.google.com/admob/ios/banner) banner ad guides. | 
|  | static const AdSize smartBanner = AdSize._( | 
|  | width: 0, | 
|  | height: 0, | 
|  | adSizeType: AdSizeType.SmartBanner, | 
|  | ); | 
|  | } | 
|  |  | 
|  | /// A mobile [BannerAd] or [InterstitialAd] for the [FirebaseAdMobPlugin]. | 
|  | /// | 
|  | /// A [MobileAd] must be loaded with [load] before it is shown with [show]. | 
|  | /// | 
|  | /// A valid [adUnitId] is required. | 
|  | abstract class MobileAd { | 
|  | /// Default constructor, used by subclasses. | 
|  | MobileAd( | 
|  | {@required this.adUnitId, | 
|  | MobileAdTargetingInfo targetingInfo, | 
|  | this.listener}) | 
|  | : _targetingInfo = targetingInfo ?? const MobileAdTargetingInfo() { | 
|  | assert(adUnitId != null && adUnitId.isNotEmpty); | 
|  | assert(_allAds[id] == null); | 
|  | _allAds[id] = this; | 
|  | } | 
|  |  | 
|  | static final Map<int, MobileAd> _allAds = <int, MobileAd>{}; | 
|  |  | 
|  | /// Optional targeting info per the native AdMob API. | 
|  | MobileAdTargetingInfo get targetingInfo => _targetingInfo; | 
|  | final MobileAdTargetingInfo _targetingInfo; | 
|  |  | 
|  | /// Identifies the source of ads for your application. | 
|  | /// | 
|  | /// For testing use a [sample ad unit](https://developers.google.com/admob/ios/test-ads#sample_ad_units). | 
|  | final String adUnitId; | 
|  |  | 
|  | /// Called when the status of the ad changes. | 
|  | MobileAdListener listener; | 
|  |  | 
|  | /// An internal id that identifies this mobile ad to the native AdMob plugin. | 
|  | /// | 
|  | /// Plugin log messages will identify this property as the ad's `mobileAdId`. | 
|  | int get id => hashCode; | 
|  |  | 
|  | /// Start loading this ad. | 
|  | Future<bool> load(); | 
|  |  | 
|  | /// Show this ad. | 
|  | /// | 
|  | /// The ad must have been loaded with [load] first. If loading hasn't finished | 
|  | /// the ad will not actually appear until the ad has finished loading. | 
|  | /// | 
|  | /// The [listener] will be notified when the ad has finished loading or fails | 
|  | /// to do so. An ad that fails to load will not be shown. | 
|  | /// | 
|  | /// anchorOffset is the logical pixel offset from the edge of the screen (default 0.0) | 
|  | /// anchorType place advert at top or bottom of screen (default bottom) | 
|  | Future<bool> show( | 
|  | {double anchorOffset = 0.0, AnchorType anchorType = AnchorType.bottom}) { | 
|  | return _invokeBooleanMethod("showAd", <String, dynamic>{ | 
|  | 'id': id, | 
|  | 'anchorOffset': anchorOffset.toString(), | 
|  | 'anchorType': anchorType == AnchorType.top ? "top" : "bottom" | 
|  | }); | 
|  | } | 
|  |  | 
|  | /// Free the plugin resources associated with this ad. | 
|  | /// | 
|  | /// Disposing a banner ad that's been shown removes it from the screen. | 
|  | /// Interstitial ads can't be programmatically removed from view. | 
|  | Future<bool> dispose() { | 
|  | assert(_allAds[id] != null); | 
|  | _allAds[id] = null; | 
|  | return _invokeBooleanMethod("disposeAd", <String, dynamic>{'id': id}); | 
|  | } | 
|  |  | 
|  | Future<bool> isLoaded() { | 
|  | return _invokeBooleanMethod("isAdLoaded", <String, dynamic>{ | 
|  | 'id': id, | 
|  | }); | 
|  | } | 
|  | } | 
|  |  | 
|  | /// A banner ad for the [FirebaseAdMobPlugin]. | 
|  | class BannerAd extends MobileAd { | 
|  | /// Create a BannerAd. | 
|  | /// | 
|  | /// A valid [adUnitId] is required. | 
|  | BannerAd({ | 
|  | @required String adUnitId, | 
|  | @required this.size, | 
|  | MobileAdTargetingInfo targetingInfo, | 
|  | MobileAdListener listener, | 
|  | }) : super( | 
|  | adUnitId: adUnitId, | 
|  | targetingInfo: targetingInfo, | 
|  | listener: listener); | 
|  |  | 
|  | final AdSize size; | 
|  |  | 
|  | /// These are AdMob's test ad unit IDs, which always return test ads. You're | 
|  | /// encouraged to use them for testing in your own apps. | 
|  | static final String testAdUnitId = Platform.isAndroid | 
|  | ? 'ca-app-pub-3940256099942544/6300978111' | 
|  | : 'ca-app-pub-3940256099942544/2934735716'; | 
|  |  | 
|  | @override | 
|  | Future<bool> load() { | 
|  | return _invokeBooleanMethod("loadBannerAd", <String, dynamic>{ | 
|  | 'id': id, | 
|  | 'adUnitId': adUnitId, | 
|  | 'targetingInfo': targetingInfo?.toJson(), | 
|  | 'width': size.width, | 
|  | 'height': size.height, | 
|  | 'adSizeType': size.adSizeType.toString(), | 
|  | }); | 
|  | } | 
|  | } | 
|  |  | 
|  | /// A full-screen interstitial ad for the [FirebaseAdMobPlugin]. | 
|  | class InterstitialAd extends MobileAd { | 
|  | /// Create an Interstitial. | 
|  | /// | 
|  | /// A valid [adUnitId] is required. | 
|  | InterstitialAd({ | 
|  | String adUnitId, | 
|  | MobileAdTargetingInfo targetingInfo, | 
|  | MobileAdListener listener, | 
|  | }) : super( | 
|  | adUnitId: adUnitId, | 
|  | targetingInfo: targetingInfo, | 
|  | listener: listener); | 
|  |  | 
|  | /// A platform-specific AdMob test ad unit ID for interstitials. This ad unit | 
|  | /// has been specially configured to always return test ads, and developers | 
|  | /// are encouraged to use it while building and testing their apps. | 
|  | static final String testAdUnitId = Platform.isAndroid | 
|  | ? 'ca-app-pub-3940256099942544/1033173712' | 
|  | : 'ca-app-pub-3940256099942544/4411468910'; | 
|  |  | 
|  | @override | 
|  | Future<bool> load() { | 
|  | return _invokeBooleanMethod("loadInterstitialAd", <String, dynamic>{ | 
|  | 'id': id, | 
|  | 'adUnitId': adUnitId, | 
|  | 'targetingInfo': targetingInfo?.toJson(), | 
|  | }); | 
|  | } | 
|  | } | 
|  |  | 
|  | /// [RewardedVideoAd] status changes reported to [RewardedVideoAdListener]s. | 
|  | /// | 
|  | /// The [rewarded] event is particularly important, since it indicates that the | 
|  | /// user has watched a video for long enough to be given an in-app reward. | 
|  | enum RewardedVideoAdEvent { | 
|  | loaded, | 
|  | failedToLoad, | 
|  | opened, | 
|  | leftApplication, | 
|  | closed, | 
|  | rewarded, | 
|  | started, | 
|  | completed, | 
|  | } | 
|  |  | 
|  | /// Signature for a [RewardedVideoAd] status change callback. The optional | 
|  | /// parameters are only used when the [RewardedVideoAdEvent.rewarded] event | 
|  | /// is sent, when they'll contain the reward amount and reward type that were | 
|  | /// configured for the AdMob ad unit when it was created. They will be null for | 
|  | /// all other events. | 
|  | typedef void RewardedVideoAdListener(RewardedVideoAdEvent event, | 
|  | {String rewardType, int rewardAmount}); | 
|  |  | 
|  | /// An AdMob rewarded video ad. | 
|  | /// | 
|  | /// This class is a singleton, and [RewardedVideoAd.instance] provides a | 
|  | /// reference to the single instance, which is created at launch. The native | 
|  | /// Android and iOS APIs for AdMob use a singleton to manage rewarded video ad | 
|  | /// objects, and that pattern is reflected here. | 
|  | /// | 
|  | /// Apps should assign a callback function to [RewardedVideoAd]'s listener | 
|  | /// property in order to receive reward notifications from the AdMob SDK: | 
|  | /// ``` | 
|  | /// RewardedVideoAd.instance.listener = (RewardedVideoAdEvent event, | 
|  | ///     [String rewardType, int rewardAmount]) { | 
|  | ///     print("You were rewarded with $rewardAmount $rewardType!"); | 
|  | ///   } | 
|  | /// }; | 
|  | /// ``` | 
|  | /// | 
|  | /// The function will be invoked when any of the events in | 
|  | /// [RewardedVideoAdEvent] occur. | 
|  | /// | 
|  | /// To load and show ads, call the load method: | 
|  | /// ``` | 
|  | /// RewardedVideoAd.instance.load(myAdUnitString, myTargetingInfoObj); | 
|  | /// ``` | 
|  | /// | 
|  | /// Later (any point after your listener callback receives the | 
|  | /// RewardedVideoAdEvent.loaded event), call the show method: | 
|  | /// ``` | 
|  | /// RewardedVideoAd.instance.show(); | 
|  | /// ``` | 
|  | /// | 
|  | /// Only one rewarded video ad can be loaded at a time. Because the video assets | 
|  | /// are so large, it's a good idea to start loading an ad well in advance of | 
|  | /// when it's likely to be needed. | 
|  | class RewardedVideoAd { | 
|  | RewardedVideoAd._(); | 
|  |  | 
|  | /// A platform-specific AdMob test ad unit ID for rewarded video ads. This ad | 
|  | /// unit has been specially configured to always return test ads, and | 
|  | /// developers are encouraged to use it while building and testing their apps. | 
|  | static final String testAdUnitId = Platform.isAndroid | 
|  | ? 'ca-app-pub-3940256099942544/5224354917' | 
|  | : 'ca-app-pub-3940256099942544/1712485313'; | 
|  |  | 
|  | static final RewardedVideoAd _instance = RewardedVideoAd._(); | 
|  |  | 
|  | /// The one and only instance of this class. | 
|  | static RewardedVideoAd get instance => _instance; | 
|  |  | 
|  | /// Callback invoked for events in the rewarded video ad lifecycle. | 
|  | RewardedVideoAdListener listener; | 
|  |  | 
|  | /// Shows a rewarded video ad if one has been loaded. | 
|  | Future<bool> show() { | 
|  | return _invokeBooleanMethod("showRewardedVideoAd"); | 
|  | } | 
|  |  | 
|  | /// Loads a rewarded video ad using the provided ad unit ID. | 
|  | Future<bool> load( | 
|  | {@required String adUnitId, MobileAdTargetingInfo targetingInfo}) { | 
|  | assert(adUnitId.isNotEmpty); | 
|  | return _invokeBooleanMethod("loadRewardedVideoAd", <String, dynamic>{ | 
|  | 'adUnitId': adUnitId, | 
|  | 'targetingInfo': targetingInfo?.toJson(), | 
|  | }); | 
|  | } | 
|  | } | 
|  |  | 
|  | /// Support for Google AdMob mobile ads. | 
|  | /// | 
|  | /// Before loading or showing an ad the plugin must be initialized with | 
|  | /// an AdMob app id: | 
|  | /// ``` | 
|  | /// FirebaseAdMob.instance.initialize(appId: myAppId); | 
|  | /// ``` | 
|  | /// | 
|  | /// Apps can create, load, and show mobile ads. For example: | 
|  | /// ``` | 
|  | /// BannerAd myBanner = BannerAd(unitId: myBannerAdUnitId) | 
|  | ///   ..load() | 
|  | ///   ..show(); | 
|  | /// ``` | 
|  | /// | 
|  | /// See also: | 
|  | /// | 
|  | ///  * The example associated with this plugin. | 
|  | ///  * [BannerAd], a small rectangular ad displayed at the bottom of the screen. | 
|  | ///  * [InterstitialAd], a full screen ad that must be dismissed by the user. | 
|  | ///  * [RewardedVideoAd], a full screen video ad that provides in-app user | 
|  | ///    rewards. | 
|  | class FirebaseAdMob { | 
|  | @visibleForTesting | 
|  | FirebaseAdMob.private(MethodChannel channel) : _channel = channel { | 
|  | _channel.setMethodCallHandler(_handleMethod); | 
|  | } | 
|  |  | 
|  | // A placeholder AdMob App ID for testing. AdMob App IDs and ad unit IDs are | 
|  | // specific to a single operating system, so apps building for both Android and | 
|  | // iOS will need a set for each platform. | 
|  | static final String testAppId = Platform.isAndroid | 
|  | ? 'ca-app-pub-3940256099942544~3347511713' | 
|  | : 'ca-app-pub-3940256099942544~1458002511'; | 
|  |  | 
|  | static final FirebaseAdMob _instance = FirebaseAdMob.private( | 
|  | const MethodChannel('plugins.flutter.io/firebase_admob'), | 
|  | ); | 
|  |  | 
|  | /// The single shared instance of this plugin. | 
|  | static FirebaseAdMob get instance => _instance; | 
|  |  | 
|  | final MethodChannel _channel; | 
|  |  | 
|  | static const Map<String, MobileAdEvent> _methodToMobileAdEvent = | 
|  | <String, MobileAdEvent>{ | 
|  | 'onAdLoaded': MobileAdEvent.loaded, | 
|  | 'onAdFailedToLoad': MobileAdEvent.failedToLoad, | 
|  | 'onAdClicked': MobileAdEvent.clicked, | 
|  | 'onAdImpression': MobileAdEvent.impression, | 
|  | 'onAdOpened': MobileAdEvent.opened, | 
|  | 'onAdLeftApplication': MobileAdEvent.leftApplication, | 
|  | 'onAdClosed': MobileAdEvent.closed, | 
|  | }; | 
|  |  | 
|  | static const Map<String, RewardedVideoAdEvent> _methodToRewardedVideoAdEvent = | 
|  | <String, RewardedVideoAdEvent>{ | 
|  | 'onRewarded': RewardedVideoAdEvent.rewarded, | 
|  | 'onRewardedVideoAdClosed': RewardedVideoAdEvent.closed, | 
|  | 'onRewardedVideoAdFailedToLoad': RewardedVideoAdEvent.failedToLoad, | 
|  | 'onRewardedVideoAdLeftApplication': RewardedVideoAdEvent.leftApplication, | 
|  | 'onRewardedVideoAdLoaded': RewardedVideoAdEvent.loaded, | 
|  | 'onRewardedVideoAdOpened': RewardedVideoAdEvent.opened, | 
|  | 'onRewardedVideoStarted': RewardedVideoAdEvent.started, | 
|  | 'onRewardedVideoCompleted': RewardedVideoAdEvent.completed, | 
|  | }; | 
|  |  | 
|  | /// Initialize this plugin for the AdMob app specified by `appId`. | 
|  | Future<bool> initialize( | 
|  | {@required String appId, | 
|  | String trackingId, | 
|  | bool analyticsEnabled = false}) { | 
|  | assert(appId != null && appId.isNotEmpty); | 
|  | assert(analyticsEnabled != null); | 
|  | return _invokeBooleanMethod("initialize", <String, dynamic>{ | 
|  | 'appId': appId, | 
|  | 'trackingId': trackingId, | 
|  | 'analyticsEnabled': analyticsEnabled, | 
|  | }); | 
|  | } | 
|  |  | 
|  | Future<dynamic> _handleMethod(MethodCall call) { | 
|  | assert(call.arguments is Map); | 
|  | final Map<dynamic, dynamic> argumentsMap = call.arguments; | 
|  | final RewardedVideoAdEvent rewardedEvent = | 
|  | _methodToRewardedVideoAdEvent[call.method]; | 
|  | if (rewardedEvent != null) { | 
|  | if (RewardedVideoAd.instance.listener != null) { | 
|  | if (rewardedEvent == RewardedVideoAdEvent.rewarded) { | 
|  | RewardedVideoAd.instance.listener(rewardedEvent, | 
|  | rewardType: argumentsMap['rewardType'], | 
|  | rewardAmount: argumentsMap['rewardAmount']); | 
|  | } else { | 
|  | RewardedVideoAd.instance.listener(rewardedEvent); | 
|  | } | 
|  | } | 
|  | } else { | 
|  | final int id = argumentsMap['id']; | 
|  | if (id != null && MobileAd._allAds[id] != null) { | 
|  | final MobileAd ad = MobileAd._allAds[id]; | 
|  | final MobileAdEvent mobileAdEvent = _methodToMobileAdEvent[call.method]; | 
|  | if (mobileAdEvent != null && ad.listener != null) { | 
|  | ad.listener(mobileAdEvent); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | return Future<dynamic>.value(null); | 
|  | } | 
|  | } | 
|  |  | 
|  | Future<bool> _invokeBooleanMethod(String method, [dynamic arguments]) async { | 
|  | final bool result = await FirebaseAdMob.instance._channel.invokeMethod( | 
|  | method, | 
|  | arguments, | 
|  | ); | 
|  | return result; | 
|  | } |