How to Create Encrypted Realm in Java using Android Studio
Repository
https://github.com/realm/realm-java
What Will I Learn?
- How to create Encrypted Realm.
- How to use the realm Configuration (How to specify the name of the realm file and other properties)
- Difference between a non-encrypted and an Encrypted Realm file.
- How to download and view realm database using Realm Studio.
- How to download files from your application using Device File Explorer in Android Studio.
Requirements
- An Integrated Development Environment(IDE) for building Android Application(e.g Anroid Studio, IntelliJ)
- Android Device/Virtual Device.
- Little Experience in working with Realm Java
- Java Programming Experience.
- Of course, willingness to learn
Resources
- Retrofit Website. https://realm.io/
- Retrofit Github. - https://github.com/realm
- Retrofit License - Apache License
- Lombok Project - https://projectlombok.org
- Realm Studio - https://realm.io/products/realm-studio/
Difficulty
- Intermediate
Tutorial Duration - 20 - 25Mins
Tutorial Content
In today's tutorial, we are going to be looking at creating an Encrypted Realm and its advantages over a non-encrypted realm.
An Encrypted realm behaves like a non-encrypted realm in terms of its workings within an application but it stays encrypted on disk. Meaning that if your application somehow gets hacked and access to your realm file is gotten, without the encrypted key used to encrypt the realm database, the details in it is useless to the hacker.
The Encrypted Realm needs a 64Bytes key. The key used to encrpyt a realm database cannot be changed once the password has been set, so take care and ensure to store the encryption properly.
In this tutorial, we would be learning by creating an application that shows a list of countries using an encrypted realm after which we will use the device file Explorer available in android studio 3.0.X upwards to download the realm file and then use Realm Studio to view the encrypted realm file.
Outline
- We add our dependencies into our gradle files.
- Include RecyclerView into MainActivity xml file.
- Create Single View for each the countries.
- Create Countries Model and use the Lombok Library.
- Create custom Adapter extending RealmRecyclerView.
- Create and populate the Realm Databases using realm configuration.
- Download the Realm Files and view them using Realm Studio.
Dependecies used
- implementation 'com.jakewharton:butterknife:8.8.1'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
The ButterKnife dependency should be placed in your application level gradle file - "build.gradle" which will make the injection of views (e.g ImageView, TextView) as easy as possible which we will be seeing in this tutorial.
- implementation 'org.projectlombok:lombok:1.16.20'
annotationProcessor 'org.projectlombok:lombok:1.16.20'
The lombok dependency also is placed in the application level gradle file which makes the generator of getter and setter methods for our model classes by just adding the annotations @Getter
for getters and @Setter
for the setter methods.
- implementation 'io.realm:android-adapters:2.1.0'
Since we will be using the RealmRecyclerViewAdapter
instead of the usual RecyclerViewAdapter
, this plugin will have to be inserted into our application level gradle file - build.gradle
Realm dependency
Steps
Head to your project level gradle file and add the classpath dependency:
classpath "io.realm:realm-gradle-plugin:5.1.0"
Next, head to your application level Gradle file "build.gradle" and add the realm-android plugin to the top of the file.
apply plugin:'realm-android'
Finally, refresh your Gradle dependencies.
After you have added the necessary dependencies, your application level Gradle file should look like this -
and your project level Gradle file should look like this
Including a RecyclerView element to our Activity layout file.
Inorder to display our Countries List, we are going to add a RecyclerView View into our activity_main.xml
file.
We also include a Textview which will be used to display a heading - Countries
with the id - countriesIndicator
and then place the RecyclerView underneath it with the line - android:layout_below="@+id/countriesIndicator"
.
<TextView
android:id="@+id/countriesIndicator"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#000"
android:padding="10dp"
android:text="Countries"
android:textColor="#fff" />
<android.support.v7.widget.RecyclerView
android:id="@+id/countriesRecView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/countriesIndicator"/>
Firstly, we have a TextView
with the id - countriesIndicator
with a black background - android:background="#000"
and a text color of white - android:textColor="#fff"
and then next we have a recyclerview with the id - countriesRecView
and it is set to appear below the texView with id - countriesIndicator
with the line - android:layout_below="@+id/countriesIndicator"
.
Create Single View for each album List
Inorder to display the countries list, we create a layout file - single_row_view
inwhich will contain a layout view on how we want all our list to be displayed.
Create a new layout file:
- right click on the res folder => New =>
Layout resource file
as shown in the image below.
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
>
<TextView
android:layout_width="0dp"
android:layout_weight="3"
android:layout_height="wrap_content"
android:text="Countries"
android:textSize="17sp"
android:padding="10dp"
android:textColor="#000"
android:id="@+id/Name"
/>
<TextView
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:text="12Years"
android:textSize="17sp"
android:padding="10dp"
android:textColor="#000"
android:id="@+id/Age"
/>
</LinearLayout>
</RelativeLayout>
Code Explanation
The above code creates a layout as below:
We have a RelativeLayout
as the root layout of this file and also we have a LinearLayout
which houses the two TeextViews with the id's - Name
,Age
for displaying the Countries name and also their age, the linearlayout is set to display its child views from left to right with the line - android:orientation="horizontal"
.
Create Model Class
We will need to create a model class which will have both getter and setter method for the required field (name and age ) of the each item in our lists which we will be needing in our recyclerview to set the details of each row.
- To create the single row layout, right click on the layout folder located under the res folder, select New and then click
Layout resource file
.
To reduce boilerplate code, we will be using the lombok library (Lombok URL) to set the getter and setter methods of the three fields by adding the @Getter
and @Setter
annotation to the respective field.
Your model class must extend realmObject
as shown in the code below.
Countries Model Class
@Getter
@Setter
public class Countries extends RealmObject {
String name;
int age;
}
Create custom Adapter
In today's tutorial, we will not be using the normal RecyclerViewAdpater
class but the RealmRecyclerViewAdapter
which makes binding of realm objects easier.
Firstly, create a new java class file MyAdapter
and extend the RealmRecyclerViewAdapter
.
public class MyAdapter extends RealmRecyclerViewAdapter<Countries, MyAdapter.MyAdapterViewHolder> {
public MyAdapter(RealmResults<Countries> countires){
super(countires, true);
}
@Override
public MyAdapterViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.single_row_view,parent,false);
return new MyAdapterViewHolder(view);
}
@Override
public void onBindViewHolder(MyAdapterViewHolder holder, int position) {
final Countries countries = getItem(position);
holder.Name.setText(countries.getName());
holder.Age.setText(countries.getAge());
}
class MyAdapterViewHolder extends RecyclerView.ViewHolder{
@BindView(R.id.Name)
TextView Name;
@BindView(R.id.Age)
TextView Age;
MyAdapterViewHolder(View view){
super(view);
ButterKnife.bind(this,view);
}
}
}
Code Explanation
onCreateViewHolder()
In this method, we inflate the layout view with our single layout file - single_row_view
file with the line - View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.single_row_view,parent,false);
and then we return the view.
onBindViewHolder()
Here, we have to set the properties of the fields of each album.
We set the details of each albums by using the setter methods gottern from our model class (countries.getName()
,countries.getAge()
).
The MyAdapterViewHolder
class uses ButterKnife
injection to inject the views from the single_row_view
layout.
Create and populate the Realm Databases using a configuration.
Next, we head over to our MainActivity.java
class file, create a Realm variable - private Realm realm;
.
In the onCreate()
method, we have to initialize realm and also get a realm instance and then we get a 64bit Key by using the SecureRandom().nextBytes()
method.
Realm.init(this);
byte[] key = new byte[64];
new SecureRandom().nextBytes(key);
And then we use the a Realm Configuration object to set the encryption key and also explicitly set the name of our realm database using - .encryptionKey(key)
,.name("realEncrypted.realm")
respectively.
RealmConfiguration encryptedConfiguration = new RealmConfiguration.Builder()
.encryptionKey(key)
.name("realEncrypted.realm")
.build();
Realm.deleteRealm(encryptedConfiguration);
NB: We use the RealmConfiguration to set some properties of the realm like the name of the realm file, and also the encryptionkey.
For the encryptedConfiguration
, we set the name of the realm file on disk as realmEncrypted.realm
.
Next, we start with a clean slate by calling the Realm.deleteRealm()
method on the encryptedConfiguration.
Lastly, we open the realm with encryption enabled by calling the getInstance()
method on the realm variables.
// Open the Realm with encryption enabled
realm = Realm.getInstance(encryptedConfiguration);
Create Realm from JSON File.
We would be using the create Realm From JSON File as explained in this tutorial -
here
- You have to first create the
raw
android resource directory:
- right click on res folder => New => Android Resource Directory
- From resource drop-down , select raw and click OK button.
- Create JSON file
- right click on the raw folder located under res folder => New => File => countries.json
Insert the following into the countries.json
file
[
{
"Name": "Nigeria",
"Age": "58 Years"
},
{
"Name": "America",
"Age": "242 Years"
}
]
This contains two JSON objects with the key of Name
and Age
.
Creating Realm Objects from JSON file
Next in our MainActivity.java
file, we call the fillUpCountriesRealm()
method that not only creates a realm database but also fills it up with the details inside of the countries.json
file created above.
fillUpCountriesRealm()
private void fillUpCountriesRealm() {
realm.executeTransaction(new Realm.Transaction() {
@Override
public void execute(Realm realm) {
InputStream inputStream = getResources().openRawResource(R.raw.countries);
try {
realm.createAllFromJson(Countries.class, inputStream);
} catch (IOException e) {
if (realm.isInTransaction())
realm.cancelTransaction();
}
}
});
}
We execute a realm transaction on the realm variable by calling the executeTransaction()
method and override the execute()
method.
We use an InputStream object - inputStream
to get the json file resource by calling the getResources()
method and then calling the openRawResource()
method with the countries
json file as an argument.
realm.createAllFromJson(Countries.class,inputStream);
creates a realm database of Countries
class and gets its values from the inputStream
.
Link Adapter to RecyclerView in MainActivity java class file
Next, we need to get all the objects in the Countries
realm database and then set it as an argument for our adapter and also set the adapter for our recycler view and lastly include a layout manager for the recyclerview.
We have to inject the recyclerview in our activity_main
layout file by placing our cursor on the layout name located on this line - `setContentView(R.layout.activity_main);' => alt + ins => Generate ButterKnife Injection, then check the check box to the left of our recyclerview view.
NB: See Image for Steps.
We then have to use begin a realm transaction to get the objects of the Countries
class, store it in a RealmResults
variable - countriesResults
and then finally commit the transaction -
realm.beginTransaction();
final RealmResults<Countries> countriesResults = realm.where(Countries.class).findAll();
realm.commitTransaction();
Finally, we have to set a vertical LinearLayoutManager
as the layoutManager of the recyclerView - countriesRecView
,we set the recyclerview to have a fixed size - countriesRecView.setHasFixedSize(true);
and we set the Adapter of the recyclerview by calling the setAdapter()
method and passing the resuls variable which now holds all the realm objects of type Countries
- countriesRecView.setAdapter(new MyAdapter(countriesResults));
countriesRecView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
countriesRecView.setHasFixedSize(true);
countriesRecView.setAdapter(new MyAdapter(countriesResults));
Complete MainActivity.java class
public class MainActivity extends AppCompatActivity {
@BindView(R.id.countriesRecView)
RecyclerView countriesRecView;
private Realm realm;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
Realm.init(this);
byte[] key = new byte[64];
new SecureRandom().nextBytes(key);
RealmConfiguration encryptedConfiguration = new RealmConfiguration.Builder()
.encryptionKey(key)
.name("realEncrypted.realm")
.build();
Realm.deleteRealm(encryptedConfiguration);
// Open the Realm with encryption enabled
realm = Realm.getInstance(encryptedConfiguration);
fillUpCountriesRealm();
realm.beginTransaction();
final RealmResults<Countries> countriesResults = realm.where(Countries.class).findAll();
realm.commitTransaction();
countriesRecView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
countriesRecView.setHasFixedSize(true);
countriesRecView.setAdapter(new MyAdapter(countriesResults));
}
private void fillUpCountriesRealm() {
realm.executeTransaction(new Realm.Transaction() {
@Override
public void execute(Realm realm) {
InputStream inputStream = getResources().openRawResource(R.raw.countries);
try {
realm.createAllFromJson(Countries.class, inputStream);
} catch (IOException e) {
if (realm.isInTransaction())
realm.cancelTransaction();
}
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
realm.close();
}
}
Download the Realm Files and view them using Realm Studio
To download our realm file, once you have your Android Device connected:
- Click on the
Device File Explorer
option located at the bottom right of your Android
- The default location of your realm file will be in data/data/"Application Pacakage Name"/files/"name of realm.realm"
(e.g data/data/com.semanienterprise.encryptedrealm/files/realEncrypted.realm)
Steps
One
Two
- Right click on the realm file => Save AS => Select location => OK
Opening Realm File With Realm Studio
After downloading the Realm Studio from Link .
- Double click the realm studio application.
- Click on the
Open Real File
option and locate the location you saved your realm file.
Steps
- One
- Click on the realm file and then you will be presented with this dialog which shows that our realm file is accurately encrypted meaning our database details are safe from hackers:
NB: To open your realm file in Realm Studio, you have to use a Hex encoded version of the key used to encrypt the realm file.
Thank you for your contribution.
While I liked the content of your contribution, I would still like to extend one advicee for your upcoming contributions:
I really enjoyed your tutorial!
Looking forward to your upcoming tutorials.
Your contribution has been evaluated according to Utopian rules and guidelines, as well as a predefined set of questions pertaining to the category.
To view those questions and the relevant answers related to your post,Click here
Need help? Write a ticket on https://support.utopian.io/.
Chat with us on Discord.
[utopian-moderator]
Thanks @portugalcoin for taking our time to moderate my post.
I promise to keep posting quality content.
Hey @edetebenezer
Thanks for contributing on Utopian.
We’re already looking forward to your next contribution!
Contributing on Utopian
Learn how to contribute on our website or by watching this tutorial on Youtube.
Want to chat? Join us on Discord https://discord.gg/h52nFrV.
Vote for Utopian Witness!