How to Create Encrypted Realm in Java using Android Studio

in #utopian-io6 years ago (edited)

realmDark.jpg

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

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 -

application Level Gradle 1.PNG

application Level Gradle 2.PNG

and your project level Gradle file should look like this

application level gradle file.PNG

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:

Screenshot_20180518-192542.png

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

  1. 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.
  1. 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.

Butterknife Injection 3.PNG

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:

  1. Click on the Device File Explorer option located at the bottom right of your Android

deviceFileExplorer.PNG

  1. 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
    fileExplorer`.PNG

  • Two

fileExplorer 2.PNG

  1. Right click on the realm file => Save AS => Select location => OK

fileExplorer 3.PNG

fileExplorer 4.PNG

Opening Realm File With Realm Studio

After downloading the Realm Studio from Link .

  1. Double click the realm studio application.
  2. Click on the Open Real File option and locate the location you saved your realm file.
Steps
  • One

realmStudio1.PNG

  1. 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:

realmStudio2.PNG

realmStudio3.PNG

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.

Curriculum

Complete Source code:

here

Sort:  

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:

  • There are parts of the code that have little explanation, try to explain as much as possible.

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!

Coin Marketplace

STEEM 0.18
TRX 0.14
JST 0.030
BTC 57983.59
ETH 3132.93
USDT 1.00
SBD 2.44