Cache User Data Securely in Flutter with Hive (NoSQL)
Ever came across a situation to store user data (or access tokens) securely in mobile app? Welcome to Hive…
We as an Application Developers, always arrive in a situation to cache user preference or access tokens for later usage in APIs. So, let’s take a look at Hive strategy.
* Why Hive and not Shared Preferences?
It’s a very generous question as SharedPreferences is pretty simple and well-known but it doesn’t provide security as such and only works with primitive data types. With Hive, we’ve the ability to store any data within an encrypted box so the data is not accessible outside the app’s context. Also, Hive is written in Dart language purely, which removes the native platform dependency and hence can be used on any platform (Android, iOS, Web). In addition to this, being NoSQL, Hive has a great performance metrics as compared to any other libraries. You can check the graph here.
- Better security with EncryptedBox.
- Faster read and writes
- Can be used with any platform.
- NoSQL, hence quick and easy to use.
- Better Documentation
- Nearly all operations are synchronous.
- Store Custom objects unlike SharedPref which only supports primitive data types. (will get hands on in this article)
* Hive Basics
First of all, Hive works in a concept of Box. Think of it as a container which will store your content in NoSQL way. Hive Box will store values in key-value pair. Let’s see some simple examples before going advanced.
Before we begin, add these dependencies in your pubspec.yaml.
The first thing we do is to open a box we desire to store/fetch values from. Then use that box same as a Map<>. Simply call put() method to store any values. A simple operation to store one key-value pair and get it’s value from box will take below code,
Yes, that’s how simple it is to work with Hive and also synchronous. Let’s take a step further and save an access token of user in an encrypted box. We’ll modify the same method to store the token and create a unique secret key to encrypt the box. One problem here is, we also have to store this secret key in secure storage or else it will defeat the purpose. That’s why we’ve included flutter_secure_storage package. The approach would be:
- Generate a secure key from Hive.
- Open a new encrypted box with this key.
- Put the access token in the box and close it.
- And finally, save this secret key to Secure storage.
Following this, our method will look something like this,
Note : FlutterSecureStorage takes only string values. Hence, we’ve used JSON encode to convert the secret key to JSON string.
You might have guessed the steps already to retrieve the token again from Hive box. I’ll leave this as a challenge for you. You can check the code here if you get stuck anywhere.
* Hive Type Adapters
We’ve finally arrived at our aim for this article. Hive has support for custom objects which means you can store your custom class objects (like UserModel class). For this, Hive uses TypeAdapters which in a sense tells Hive how to store and parse this custom objects. Hive can generate TypeAdapters for almost any class.
Note: You can also create these classes manually. But it’s 2020.
Now, let’s take a simple model class.
We’ve to extend this class from HiveObject and annotate class with HiveType. Also annotate class fields with HiveField annotation(Only annotate fields which you want to store in Hive).
I’ve not annotated “role” field as I do not wish to store it in Hive. Also, there are some rules when it comes to giving HiveField values.
- Each field should have unique integer value.
- If you wish to add any extra properties to the class later, don’t change the values of existing fields.
- If you have a property which is another class, then it’s HiveType id should be unique.
After this, your IDE might be yelling at you at line no 3. Don’t worry we’ll solve that error in this step. We have to have a generator class for our model that will actually handle parsing of these fields. That’s why we included hive_generator and build_runner packages in dev_dependencies. Just run this simple command in your terminal under project root.
flutter packages pub run build_runner build
You will see one file as <model_name>.g.dart. This is a generated file which will be used by Hive whenever dealing with this model class. Don’t edit or update anything in this file manually.
The only thing remaining now is to register this type adapter with Hive. Put this line in main.dart where we initialized hive first.
* Perform Actual Caching
Now that we have our TypeAdapter ready, we can store our data. It’s the same as we saw in Hive Basics section. We’ll just initialize our model and put it in the box.
As simple as that. No code difference for storing custom objects. We just had to create our TypeAdapter and booom! You could also store this data in an encrypted box but as I’m not storing any confidential information, it is an overkill for me.
* More Usecases for Hive
You can use Hive for almost any data storage but keep in mind that the simplicity lies in NoSQL structure. If you have any relational data think for other packages like sqflite. If you’re building any social media clones like Instagram, you can also store some post feeds as a cache in Hive with TypeAdapters. You can take a look at the hive documentation here.
Hope you’ve learned the usage of Hive with flutter and some caching tips. Any suggestions are welcome in the response or on LinkedIn.