A boilerplate has been created to facilitate development with Kuzzle and Flutter: https://github.com/kuzzleio/flutter-boilerplate
Flutter is a framework made by Google which allows you to easily make mobile application compatible with Android and IOS.
The boilerplate is using the Dart Kuzzle SDK to facilitate queries between your mobile application and Kuzzle Backend.
Let's see what the boilerplate contains and how it works.
TL;DR
This boilerplate allows you to start from a flutter project with the Kuzzle Dart SDK and a Login / token handling already done.
What's inside
The boilerplate contains 3 screens:
- Splash screen
- Login screen
- Home screen
The Login is handled by Kuzzle and the communication between the app and Kuzzle backend is done with the embedded Kuzzle Dart SDK.
Then an intern mechanism will handle if the token of the logged user expires and if so, redirect to the Login screen.
In detail
SDK Instance
First of all we have our Kuzzle Dart SDK as dependency in our pubspec.yml
dependencies:
flutter:
sdk: flutter
kuzzle: ^3.0.0
which is instantiated in app.dart and in this case we use the Web Socket protocol but you can use Http (see more here)
@override
void initState() {
super.initState();
final proto = WebSocketProtocol(
Uri(
scheme: Config.scheme,
host: Config.host,
port: Config.port,
),
);
kuzzle = Kuzzle(proto);
}
and given to an InheritedWidget which contains the app so the sdk can be accessed anywhere from its children.
@override
Widget build(BuildContext context) => KuzzleSdk(
kuzzle: kuzzle!,
...
To access the SDK simply do
KuzzleSdk.of(context).kuzzle
Check if logged in before going to home
Between the splashscreen screen and the login/home screen there is a step in the middle to check weather or not we should display the login or home widget.
Inside root.dart we check if a token has been written in the secured storage and call the API route checkToken to see if this token is expired or not. But first we need to connect to our Kuzzle instance as we are using Web Socket.
@override
void didChangeDependencies() async {
super.didChangeDependencies();
final kuzzle = KuzzleSdk.of(context).kuzzle;
try {
await kuzzle.connect();
...
Note that we do this in the didChangeDependencies instead of initState method because we need the context post build to be able to access our InheritedWidget.
Next we check if we have a token and use our SDK to call the checkToken API route:
final checkTokenResponse = await kuzzle.auth.checkToken(storedToken);
If the token is valid we then get the current user information:
final currentUser = await kuzzle.auth.getCurrentUser();
And we update this user which is contained in another InheritedWidget which is a child of our KuzzleSdk InheritedWidget:
widget.updateUser?.call(currentUser);
More explanation about updating a value in an InheritedWidget
If you take a closer look at app.dart you can see that the child of our KuzzleSdk is another InheritedWidget called CurrentUser.
@override
Widget build(BuildContext context) => KuzzleSdk(
kuzzle: kuzzle!,
child: CurrentUser(
user: _currentUser,
Because when we start the app we don't have the currentUser yet so we need a way for the child to update the value of the CurrentUser widget. An InheritedWidget is supposed to be immutable so we can't just set a new value by doing something like:
CurrentUser.of(context).user = ...
Instead we are going to pass a callback to our child and in this callback we will call setState with the new value passed by the child. This will have the effect to rebuild App with the new value inside CurrentUser.
Root( updateUser: (user) { setState(() { _currentUser = user; }); }, ),
Let's get back on track
Now that we know if we are loggued in or not we can decide which widget we should show.
For that we use a state to know if we are indeed logged in or not. This state is actually an enum so according to its value we return either the Login widget, the Home widget or the Splashscreen
@override
Widget build(BuildContext context) {
if (tokenState == TokenState.done) {
return const HomePage();
} else if (tokenState == TokenState.expired) {
return const Login();
}
return const Scaffold(
body: Center(
child: SplashScreen(),
),
);
}
Afterwards
The rest is pretty easy to understand, you can take a look at the Login widget which will use the SDK to login to Kuzzle:
final res = await KuzzleSdk.of(context)
.kuzzle
.auth
.login(
'local',
{
'username': _emailController.text
.trim()
.toLowerCase(),
'password': _passwordController.text,
},
expiresIn: '24h',
);
and the Home widget is made of a BottomNavigationBar.
Resources
github boilerplate: https://github.com/kuzzleio/flutter-boilerplate
Kuzzle Dart SDK: https://pub.dev/packages/kuzzle
Kuzzle Dart SDK documentation: https://docs.kuzzle.io/sdk/dart/3
Kuzzle documentation: https://docs.kuzzle.io/