I've build a simple Splash screen. I'm using this package. Now, I'm trying to add version checker via Firebase Remote Config to my Splash Screen. I've written simple version checker code:
Future<bool> versionCheck(context) async {
//Get Current installed version of app
final PackageInfo info = await PackageInfo.fromPlatform();
double currentVersion = double.parse(info.version.trim().replaceAll(".", ""));
//Get Latest version info from firebase config
final FirebaseRemoteConfig _remoteConfig = FirebaseRemoteConfig.instance;
// Using default duration to force fetching from remote server.
try {
await _remoteConfig.setConfigSettings(RemoteConfigSettings(
// cache refresh time
fetchTimeout: const Duration(seconds: 1),
// a fetch will wait up to 3 seconds before timing out
minimumFetchInterval: const Duration(seconds: 3),
));
await _remoteConfig.fetchAndActivate();
_remoteConfig.getString('force_update_current_version');
double newVersion = double.parse(_remoteConfig
.getString('force_update_current_version')
.trim()
.replaceAll(".", ""));
if (newVersion > currentVersion) {
return false;
} else {
return true;
}
} catch (exception) {
return false;
}
}
I've tested it on my another screen. It works fine.
When I try to add this control to my Splash screen, it says type 'Null' is not a subtype of type 'Widget'
I'm getting my show
boolean from SharedPreferences via my checkOnBoarding()
method and works well, but when I try to add version control, I fail.
Here it is my Splash Screen code:
class SplashScreen extends StatefulWidget
{
@override
_SplashScreenState createState() => _SplashScreenState();
}
class _SplashScreenState extends State<SplashScreen> {
bool show = true;
bool versionOK = false;
@override
void initState() {
checkVersion();
super.initState();
}
@override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () {
return Future.value(false);
},
child: AnimatedSplashScreen(
backgroundColor: Colors.white,
splash: "images/my-logo.png",
nextScreen: FutureBuilder(
future: checkOnBoarding(),
builder: (context, snapshot) {
if (snapshot.hasData) {
if(snapshot.data == true){
if(versionOK){
return MainScreen();
} else {
return showVersionDialog(context);
}
}
else{
return IntroScreen();
}
} else {
return CircularProgressIndicator();
}
},
),
splashTransition: SplashTransition.sizeTransition,
duration: 3000,
),
);
}
Future<bool> checkVersion() async{
versionOK = await versionCheck(context);
return versionOK;
}
Future<bool> checkOnBoarding() async{
final prefs = await SharedPreferences.getInstance();
show = prefs.getBool('ON_BOARDING') ?? false;
return show;
}
showVersionDialog(context) {
Future.delayed(Duration.zero,(){
showDialog<String>(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
String title = "New Update Available";
String message =
"There is a newer version of app available please update it now.";
String btnLabel = "OK";
return Platform.isIOS
? new CupertinoAlertDialog(
title: Text(title),
content: Text(message),
actions: <Widget>[
ElevatedButton(
child: Text(btnLabel),
onPressed: () {
exit(0);
},
),
],
)
: new AlertDialog(
title: Text(title),
content: Text(message),
actions: <Widget>[
ElevatedButton(
child: Text(btnLabel),
onPressed: () {
SystemNavigator.pop();
},
),
],
);
},
);
});
}
}
So as you see, after I get my show
boolean from SharedPreference, I want to check versionOK
and if it false
, I want to show a non-dissmisable dialog with one button (via my showVersionDialog
method). If it comes true, I want to navigate my Main Screen.
What am I missing?
CodePudding user response:
The issue is showVersionDialog
doesn't return a widget.
showVersionDialog(context) {
_dialog(context);
return Scaffold();
}
_dialog(context) {
Future.delayed(Duration.zero, () {
showDialog<String>(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
String title = "New Update Available";
String message =
"There is a newer version of app available please update it now.";
String btnLabel = "OK";
return AlertDialog(
title: Text(title),
content: Text(message),
actions: <Widget>[
ElevatedButton(
child: Text(btnLabel),
onPressed: () {},
),
],
);
},
);
});
}
CodePudding user response:
The problem is this line:
return showVersionDialog(context);
A builder wants to return a widget, but your showVersionDialog method just opens a Dialog and doesn't return a widget.
I would remove this if:
if(snapshot.data == true){
if(versionOK){
return MainScreen();
} else {
return showVersionDialog(context);
}
}
else{
return IntroScreen();
}
and replace it with this:
return snapshot.data ? MainScreen() : IntroScreen();
Instead in your initState you can check for the version and if it's not okay you can show your dialog:
@override
void initState() {
WidgetsBinding.instance.addPostFrameCallback((_) async {
versionOK = await checkVersion();
if (!versionOK) {
await showVersionDialog(context);
}
});
super.initState();
}
CodePudding user response:
This error occurs when you need to return a widget but instead the program receives nothing. Unless I'm mistaken, I think the error comes from the showAlertDialog. Try adding return before the showAlertDialog's body.
showVersionDialog(context) {
// I'm not sure you need the Future.delayed. I would directly
// return the show dialog
**return** showDialog<String>(
context: context,
.........
Hope this helps