This tutorial shows you how to integrate your Flutter application with Firebase Remote Config to modify the application's appearance and behavior without releasing an update.
The layout of an application is very important for users. Sometimes, you may want to change the layout of your application with the hope for improving the user experience. However, you may be not sure whether the new layout change will provide a better experience or vice versa. If you find out that the users don't like the new layout, you may want to revert to the old layout. It can be done by rolling out an update to the users. However, releasing too many updates is not a good thing and some users may not update the application immediately.
One of the possible solutions for that problem is by storing the config in a server and the application needs to fetch the config to determine the layout. You can develop your own backend API for that purpose. But if you don't want to do that, you can use a 3rd party service such as Firebase Remote Config.
The Firebase Remote Config allows you to define several parameters which can be done from the Firebase Console or Firebase Remote Config API which should be called from the backend of your application. The application will fetch the parameters and use them to determine its layout and/or behavior. If you're using Flutter, there is already a package from the Firebase Team that makes it easier to use Remote Config in a Flutter application.
Integrate Firebase to Flutter Application
Like using other Firebase services, you need to integrate your Firebase account with the application. Basically, what you need to do is create a Firebase project and add an application to the Firebase console. Then, download and copy the config files to your project. You can read the details in our tutorial about integration with Firebase services in Flutter.
To make it easier to use Firebase Remote Config, we are going to use firebase_remote_config
package. Add the below dependency to your pubspec.yaml
file.
dependencies:
firebase_remote_config: ^0.6.0
Add Parameters in Firebase Remote Config
In order to use Firebase Remote Config, you need to define parameters. To do so, you can open the Remote Config menu from the navigation sidebar. If you haven't created any parameter, you can create one by using the form. For example, we are going to create a parameter whose name is new_color_enabled
with false
as the default value. You can also add a description about the parameter. After that, click the Add Parameter button.
For each parameter, you can define several conditions that will have different values from the default value. For example, we only want to enable the new color if the platform is Android. To do so, you can click the edit icon of the parameter. Then, click the Add value for condition button and choose Define new condition.
A form will be displayed and you need to set the name and the conditions where the condition should be applied. In this example, we want to set the value of new_color_enabled
to true
only if the platform is Android. For this case, choose Platform on the left dropdown and then choose Android on the right dropdown.
After the condition has been created, you can set a different value for that condition.
If there are multiple conditions that evaluate to true
, the first one with the highest priority will be used. You can see the list of conditions on the Conditions tab and change the priority by dragging and dropping the conditions.
Get Parameters In Flutter Application
Having created the parameters and integrated Remote Config to your Flutter application, now it's time to get the values of the parameters. First, you need to import the package in the file where you want to access the values from Firebase.
import 'package:firebase_remote_config/firebase_remote_config.dart';
After that, you can get the instance of RemoteConfig
by calling RemoteConfig.instance
which returns Future<RemoteConfig>
. Assuming we have a state variable _remoteConfig
, you can get the instance like the code below.
_remoteConfig = await RemoteConfig.instance;
Firebase recommends us to define default values for each parameter. If you try to get a parameter that's not defined in the Firebase console, the default value for the parameter will be used.
final Map<String, dynamic> defaults =<<String, dynamic>{
'new_color_enabled': false
};
await _remoteConfig.setDefaults(defaults);
After that, you can fetch the values from Firebase by calling the fetch
method of RemoteConfig
. The method has an optional named argument expiration
whose type is Duration
, used to set the expiration time. After the values have been fetched, they do not take effect automatically. You need to call activateFetched
so that the fetched values can take effect.
You can also set the configurations for the RemoteConfig
instance by calling setConfigSettings
with RemoteConfigSettings
as the value. It has two properties:
int minimumFetchIntervalMillis
: The minimum fetch interval for Remote Config in milliseconds, defaults to 43200000 (12 hours).int fetchTimeoutMillis
: The fetch timeout for Remote Config in milliseconds, defaults to 60000 (1 minute).
_remoteConfig.setConfigSettings(RemoteConfigSettings(
minimumFetchIntervalMillis: 21600000,
fetchTimeoutMillis: 30000,
));
Lastly, you need to get the value of a parameter. The firebase_remote_config
package provides several methods for that purpose and you should select one based on the value type. Below are the type-specific methods.
Method | Type | Default Value |
---|---|---|
getString |
String |
'' (empty string) |
getBool |
bool |
false |
getInt |
int |
0 |
getDouble |
double |
0.0 |
The value of new_color_enabled
parameter in this tutorial is a bool
. Therefore, we can use the getBool
method. If the parameter is not found, the default value from the map that you pass when calling setDefaults
will be used. If the map also doesn't contain the value, the default value for the type (as shown on the table above) will be used.
_remoteConfig.getBool('new_color_enabled');
If you want to get the value of all parameters as a map, you can call the getAll
method, which returns Map<String, RemoteConfigValue>
. The RemoteConfigValue
itself has some methods for converting the value to a specific type: asString
, asInt
, asDouble
, asBool
. If a value is null or cannot be parsed to the given type, it will use the default value which is the same as the default value on the table above for the respective type.
_remoteConfig.getAll();
Get Latest Fetch Information
Another thing you may need to know is the latest fetch time and status. That information can be obtained easily from the lastFetchTime
and lastFetchStatus
properties of the RemoteConfig
.
print('Last fetch status: ' + _remoteConfig.lastFetchStatus.toString());
print('Last fetch time: ' + _remoteConfig.lastFetchTime.toString());
Handle Layout When Fetching Data to Remote Config
Since it may take a few milliseconds (or seconds if the connection is slow) to get the values from Firebase, you need to determine how to handle the layout while the application is fetching data. There are some options you can choose depending on the requirements or your preference.
- Update the data after new values have been activated. In this scenario, you load your application first and render the layout using the default values. After fetching data to Firebase have been done and the fetched values have been activated, the layout will be refreshed. The drawback of this method is the user may see the layout changes while using the application.
- Apply value the next time the application is launched. With this option, if the application hasn't got the values from Firebase, it will use the default values. After that, the application fetches the latest data from Firebase, but instead of activating the values immediately, it stores the values somewhere and uses them the next time the application is launched. The drawback of this option is the user may not get the layout changes immediately.
- Show loading. If you want to apply the layout changes as soon as possible without giving weird layout changes to the users, you can show a loading icon first while the application is fetching data from Firebase. After the new values have been applied, the user will see the new layout based on the values from Firebase Remote Config.
Full Code
Below is an example of a page whose color depends on a parameter value from Firebase Remote Config. There is a state variable _isLoading
which is used to keep track whether fetching to the Firebase service has been done. If not, a loading indicator will be displayed.
import 'package:flutter/material.dart';
import 'package:firebase_remote_config/firebase_remote_config.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Woolha.com Flutter Tutorial',
home: FirebaseRemoteConfigExample(),
);
}
}
class FirebaseRemoteConfigExample extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return _FirebaseRemoteConfigExampleState ();
}
}
class _FirebaseRemoteConfigExampleState extends State<FirebaseRemoteConfigExample> {
static RemoteConfig _remoteConfig;
bool _isLoading = true;
Color _color;
@override
void initState() {
super.initState();
_initializeRemoteConfig();
}
_initializeRemoteConfig() async {
if (_remoteConfig == null) {
_remoteConfig = await RemoteConfig.instance;
final Map<String, dynamic> defaults = <String, dynamic>{
'new_color_enabled': false
};
await _remoteConfig.setDefaults(defaults);
_remoteConfig.setConfigSettings(RemoteConfigSettings(
minimumFetchIntervalMillis: 1,
fetchTimeoutMillis: 1,
));
await _fetchRemoteConfig();
}
setState(() {
_isLoading = false;
});
}
Future<void> _fetchRemoteConfig() async {
try {
await _remoteConfig.fetch(expiration: const Duration(minutes: 1));
await _remoteConfig.activateFetched();
print('Last fetch status: ' + _remoteConfig.lastFetchStatus.toString());
print('Last fetch time: ' + _remoteConfig.lastFetchTime.toString());
print('New color enabled?: ' + _remoteConfig.getBool('new_color_enabled').toString());
setState(() {
_color = _remoteConfig.getBool('new_color_enabled') ? Colors.teal : Colors.blue;
});
} catch (e) {
print('Error: ${e.toString()}');
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: _isLoading
? null
: AppBar(
title: const Text('Woolha.com Flutter Tutorial'),
backgroundColor: _color,
),
body: _isLoading
? const Center(child: const CircularProgressIndicator())
: SizedBox(
width: double.infinity,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'Woolha.com',
style: TextStyle(color: _color, fontSize: 48),
),
OutlinedButton(
onPressed: () => _fetchRemoteConfig(),
child: Text('Refresh', style: TextStyle(color: _color)),
)
],
),
),
);
}
}
Summary
The Firebase Remote Config is an easy solution if you want to perform conditional layout or behavior change to your Flutter applications without the need to release a new update. The usage is quite simple. You need to configure the parameters in the Firebase Console, integrate Firebase to your Flutter application, and access the parameters from the Remote Config service with the help of firebase_remote_config
package.
You can also read our tutorials about: