Skip to content
This repository has been archived by the owner on Mar 12, 2022. It is now read-only.

Fix bug #114. #126

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ class BannerAdController(
"loadAd" -> {
channel.invokeMethod("loading", null)
loadRequested?.let { it(result) }
// Actually, no ads will be loaded here, so return false immediately
result.success(false)
}
else -> result.notImplemented()
}
Expand Down
16 changes: 16 additions & 0 deletions lib/src/banner/banner_ad_widget.dart
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,8 @@ class _BannerAdState extends State<BannerAd>
BannerAdOptions get options => widget.options;
StreamSubscription? _onEventSub;

late Future _initFuture;

@override
void initState() {
super.initState();
Expand All @@ -215,6 +217,8 @@ class _BannerAdState extends State<BannerAd>
}
});
if (!controller.isLoaded) controller.load(timeout: widget.loadTimeout);

_initFuture = controller.waitForInitFinish();
}

@override
Expand Down Expand Up @@ -257,6 +261,18 @@ class _BannerAdState extends State<BannerAd>
assertPlatformIsSupported();
assertVersionIsSupported();

return FutureBuilder<void>(
future: _initFuture,
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return _bannerAdWidget();
} else {
return SizedBox();
}
});
}

Widget _bannerAdWidget() {
return LayoutBuilder(
builder: (context, consts) {
double height = widget.size.size.height;
Expand Down
38 changes: 27 additions & 11 deletions lib/src/banner/controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,8 @@ class BannerAdController extends LoadShowAd<BannerAdEvent>
/// For more info, [read the documentation](https://github.com/bdlukaa/native_admob_flutter/wiki/Using-the-controller-and-listening-to-banner-events#listening-to-events)
Stream<Map<BannerAdEvent, dynamic>> get onEvent => super.onEvent;

FutureSyncExecutor _executor = FutureSyncExecutor();

/// Creates a new native ad controller
BannerAdController({
Duration loadTimeout = kDefaultLoadTimeout,
Expand All @@ -167,7 +169,15 @@ class BannerAdController extends LoadShowAd<BannerAdEvent>
/// Initialize the controller. This can be called only by the controller
void init() {
channel.setMethodCallHandler(_handleMessages);
MobileAds.pluginChannel.invokeMethod('initBannerAdController', {'id': id});
_executor.exec(() async {
await MobileAds.pluginChannel.invokeMethod('initBannerAdController', {'id': id});
}, null);
}

Future<void> waitForInitFinish() async {
return await _executor.exec(() {
return;
}, null);
}

/// Dispose the controller to free up resources.
Expand Down Expand Up @@ -203,6 +213,9 @@ class BannerAdController extends LoadShowAd<BannerAdEvent>
});
break;
case 'onAdLoaded':
if (isLoaded) {
break;
}
isLoaded = true;
onEventController.add({BannerAdEvent.loaded: call.arguments});
break;
Expand All @@ -227,16 +240,19 @@ class BannerAdController extends LoadShowAd<BannerAdEvent>
ensureAdNotDisposed();
assertMobileAdsIsInitialized();
if (!debugCheckAdWillReload(isLoaded, force)) return false;
isLoaded = (await channel.invokeMethod<bool>('loadAd').timeout(
timeout ?? this.loadTimeout,
onTimeout: () {
if (!onEventController.isClosed && !isLoaded)
onEventController.add({
BannerAdEvent.loadFailed: AdError.timeoutError,
});
return false;
},
))!;
isLoaded = await _executor.exec(() async {
return channel.invokeMethod<bool>('loadAd').timeout(
timeout ?? this.loadTimeout,
onTimeout: () {
if (!onEventController.isClosed && !isLoaded) {
onEventController.add({
BannerAdEvent.loadFailed: AdError.timeoutError,
});
}
return false;
},
);
}, null);
if (isLoaded) lastLoadedTime = DateTime.now();
return isLoaded;
}
Expand Down
40 changes: 24 additions & 16 deletions lib/src/native/controller/controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,9 @@ class NativeAdController extends LoadShowAd<NativeAdEvent>
/// For more info, read the [documentation](https://github.com/bdlukaa/native_admob_flutter/wiki/Custom-mute-this-ad#check-if-custom-mute-this-ad-is-available)
bool get isCustomMuteThisAdEnabled => _customMuteThisAdEnabled;

/// Asynchronous task synchronous executor
FutureSyncExecutor _syncExecutor= FutureSyncExecutor();

/// Listen to the events the controller throws
///
/// Usage:
Expand Down Expand Up @@ -261,7 +264,9 @@ class NativeAdController extends LoadShowAd<NativeAdEvent>
/// Initialize the controller. This can be called only by the controller
void init() {
channel.setMethodCallHandler(_handleMessages);
MobileAds.pluginChannel.invokeMethod('initNativeAdController', {'id': id});
_syncExecutor.exec(() async {
await MobileAds.pluginChannel.invokeMethod('initNativeAdController', {'id': id});
}, null);
}

/// Dispose the controller to free up resources.
Expand Down Expand Up @@ -393,21 +398,24 @@ class NativeAdController extends LoadShowAd<NativeAdEvent>
assertMobileAdsIsInitialized();
if (!debugCheckAdWillReload(isLoaded, force)) return false;
unitId ??= MobileAds.nativeAdUnitId ?? MobileAds.nativeAdTestUnitId;
isLoaded = (await channel.invokeMethod<bool>('loadAd', {
'unitId': unitId,
'options': (options ?? NativeAdOptions()).toJson(),
'nonPersonalizedAds': nonPersonalizedAds ?? this.nonPersonalizedAds,
'keywords': keywords,
}).timeout(
timeout ?? this.loadTimeout,
onTimeout: () {
if (!onEventController.isClosed && !isLoaded)
onEventController.add({
NativeAdEvent.loadFailed: AdError.timeoutError,
});
return false;
},
))!;
isLoaded = await _syncExecutor.exec(() async {
// Invoke the loadAd method after initializing MethodChannel
return await channel.invokeMethod<bool>('loadAd', {
'unitId': unitId,
'options': (options ?? NativeAdOptions()).toJson(),
'nonPersonalizedAds': nonPersonalizedAds ?? this.nonPersonalizedAds,
'keywords': keywords,
}).timeout(
timeout ?? this.loadTimeout,
onTimeout: () {
if (!onEventController.isClosed && !isLoaded)
onEventController.add({
NativeAdEvent.loadFailed: AdError.timeoutError,
});
return false;
},
);
}, null);
if (isLoaded) lastLoadedTime = DateTime.now();
return isLoaded;
}
Expand Down
20 changes: 20 additions & 0 deletions lib/src/utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -290,3 +290,23 @@ class ServerSideVerificationOptions {
'customData': this.customData,
};
}

/// Future synchronous executor
class FutureSyncExecutor {
Future? future;

Future exec(Function function, List<dynamic>? positionalArguments,
[Map<Symbol, dynamic>? namedArguments]) {
final applyFunction = () {
return Function.apply(function, positionalArguments, namedArguments);
};

if (future == null) {
future = Future(applyFunction);
return future!;
} else {
future = future!.then((value) => applyFunction());
return future!;
}
}
}