如何解决 Flutter / Admob 的 "Ad.load to be called before AdWidget is inserted into the tree" 问题?
How to fix the issue "Ad.load to be called before AdWidget is inserted into the tree" issue with Flutter / Admob?
我在 Flutter 上使用 google_mobile_ads: ^1.1.0
版本并在此处观看视频:
https://www.youtube.com/watch?v=m0d_pbgeeG8
除了视频方面的一些小改动(我想与最近的 API 改动相比还没有完全更新)我现在有以下代码:
void main() async {
WidgetsFlutterBinding.ensureInitialized();
final initFuture = MobileAds.instance.initialize();
final adState = AdState(initFuture);
await SystemChrome.setPreferredOrientations(<DeviceOrientation>[
DeviceOrientation.portraitUp,
DeviceOrientation.portraitDown
]).then((_) => runApp(
MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => Something()),
...some other ChangeNotifierProvider...,
Provider<AdState>(create: (_) => adState)
],
child: const MyApp()
),
));
}
与 AdState
:
import 'dart:io';
import 'package:google_mobile_ads/google_mobile_ads.dart';
class AdState {
Future<InitializationStatus> initialisation;
AdState(this.initialisation);
String get bannerAdUnitId => Platform.isAndroid
? 'ca-app-pub-3940256099942544/6300978111'
: 'ca-app-pub-3940256099942544/2934735716'; // ios
BannerAdListener get adListener => _adListener;
final BannerAdListener _adListener = BannerAdListener(
// Called when an ad is successfully received.
onAdLoaded: (Ad ad) => print('Ad loaded: ${ad.adUnitId}.'),
onAdClosed: (Ad ad) {
ad.dispose();
print('Ad closed: ${ad.adUnitId}.');
},
// Called when an ad request failed.
onAdFailedToLoad: (Ad ad, LoadAdError error) {
ad.dispose();
print('Ad failed to load: : ${ad.adUnitId}, $error');
},
// Called when an ad opens an overlay that covers the screen.
onAdOpened: (Ad ad) => print('Ad opened: ${ad.adUnitId}.'),
// Called when an impression occurs on the ad.
onAdImpression: (Ad ad) => print('Ad impression: ${ad.adUnitId}.'),
);
}
然后在首页widget状态class:
BannerAd? banner;
@override
void didChangeDependencies() {
super.didChangeDependencies();
final adState = Provider.of<AdState>(context);
adState.initialisation.then((status) {
setState(() {
banner = BannerAd(
adUnitId: adState.bannerAdUnitId,
size: AdSize.banner,
request: const AdRequest(),
listener: adState.adListener
)..load();
});
});
}
@override
Widget build(BuildContext context) {
...somewhere in the middle...
if (banner == null)
const SizedBox(height: 50)
else
SizedBox (height:50, child: AdWidget(ad: banner!)),
....
}
我得到的错误是:
AdWidget requires Ad.load to be called before AdWidget is inserted
into the tree
load()
方法在上面的 didChangeDependencies()
方法中被调用,当然它 returns 一个 Future
所以我认为当 build()
正在 运行。我该如何解决?
您只能在 BannerAd
加载后才能使用 AdWidget
,而不是 BannerAd
不为空。
因此,请尝试使用 flag
作为加载状态,如以下代码片段所示:
BannerAd? banner;
bool _bannerIsLoaded = false;
@override
void didChangeDependencies() {
super.didChangeDependencies();
final adState = Provider.of<AdState>(context);
adState.initialisation.then((status) {
setState(() {
banner = BannerAd(
adUnitId: adState.bannerAdUnitId,
size: AdSize.banner,
request: const AdRequest(),
listener: adState.adListener
)..load();
_bannerIsLoaded = true;
});
});
}
@override
Widget build(BuildContext context) {
...somewhere in the middle...
if (banner != null && _bannerIsLoaded)
SizedBox (height:50, child: AdWidget(ad: banner!)),
else
const SizedBox(height: 50)
....
}
我在 Flutter 上使用 google_mobile_ads: ^1.1.0
版本并在此处观看视频:
https://www.youtube.com/watch?v=m0d_pbgeeG8
除了视频方面的一些小改动(我想与最近的 API 改动相比还没有完全更新)我现在有以下代码:
void main() async {
WidgetsFlutterBinding.ensureInitialized();
final initFuture = MobileAds.instance.initialize();
final adState = AdState(initFuture);
await SystemChrome.setPreferredOrientations(<DeviceOrientation>[
DeviceOrientation.portraitUp,
DeviceOrientation.portraitDown
]).then((_) => runApp(
MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => Something()),
...some other ChangeNotifierProvider...,
Provider<AdState>(create: (_) => adState)
],
child: const MyApp()
),
));
}
与 AdState
:
import 'dart:io';
import 'package:google_mobile_ads/google_mobile_ads.dart';
class AdState {
Future<InitializationStatus> initialisation;
AdState(this.initialisation);
String get bannerAdUnitId => Platform.isAndroid
? 'ca-app-pub-3940256099942544/6300978111'
: 'ca-app-pub-3940256099942544/2934735716'; // ios
BannerAdListener get adListener => _adListener;
final BannerAdListener _adListener = BannerAdListener(
// Called when an ad is successfully received.
onAdLoaded: (Ad ad) => print('Ad loaded: ${ad.adUnitId}.'),
onAdClosed: (Ad ad) {
ad.dispose();
print('Ad closed: ${ad.adUnitId}.');
},
// Called when an ad request failed.
onAdFailedToLoad: (Ad ad, LoadAdError error) {
ad.dispose();
print('Ad failed to load: : ${ad.adUnitId}, $error');
},
// Called when an ad opens an overlay that covers the screen.
onAdOpened: (Ad ad) => print('Ad opened: ${ad.adUnitId}.'),
// Called when an impression occurs on the ad.
onAdImpression: (Ad ad) => print('Ad impression: ${ad.adUnitId}.'),
);
}
然后在首页widget状态class:
BannerAd? banner;
@override
void didChangeDependencies() {
super.didChangeDependencies();
final adState = Provider.of<AdState>(context);
adState.initialisation.then((status) {
setState(() {
banner = BannerAd(
adUnitId: adState.bannerAdUnitId,
size: AdSize.banner,
request: const AdRequest(),
listener: adState.adListener
)..load();
});
});
}
@override
Widget build(BuildContext context) {
...somewhere in the middle...
if (banner == null)
const SizedBox(height: 50)
else
SizedBox (height:50, child: AdWidget(ad: banner!)),
....
}
我得到的错误是:
AdWidget requires Ad.load to be called before AdWidget is inserted into the tree
load()
方法在上面的 didChangeDependencies()
方法中被调用,当然它 returns 一个 Future
所以我认为当 build()
正在 运行。我该如何解决?
您只能在 BannerAd
加载后才能使用 AdWidget
,而不是 BannerAd
不为空。
因此,请尝试使用 flag
作为加载状态,如以下代码片段所示:
BannerAd? banner;
bool _bannerIsLoaded = false;
@override
void didChangeDependencies() {
super.didChangeDependencies();
final adState = Provider.of<AdState>(context);
adState.initialisation.then((status) {
setState(() {
banner = BannerAd(
adUnitId: adState.bannerAdUnitId,
size: AdSize.banner,
request: const AdRequest(),
listener: adState.adListener
)..load();
_bannerIsLoaded = true;
});
});
}
@override
Widget build(BuildContext context) {
...somewhere in the middle...
if (banner != null && _bannerIsLoaded)
SizedBox (height:50, child: AdWidget(ad: banner!)),
else
const SizedBox(height: 50)
....
}