Sharing a Realm via QR Code with ZXing

This post originally appeared on the Pie Eating Ninjas’ Blog and has been updated here as a guest post by the original author Pieter Nijs.

Realm offers a nice technique to share Realms with other users. The idea is that you can provide a token that another user can use to connect to your data store. In this blog post we will use this flow in combination with a QR code - generated by ZXing - to let another user connect to a data store and start a chat (or anything).

The problem with demos

I’ve been playing with Realm for some time now. With this platform it is as easy as it can get for developers to create apps that do real-time data synchronization. Sometimes it does feel a bit like magic! And so I created some stuff with it – typical demo stuff. Most of the time, these demos do something like this:

  • Connect to a Realm with User A
  • Display an object from that Realm on the screen
  • Take a second device
  • Connect to the same Realm with User A
  • Display the same object from that Realm on the screen
  • Make changes to the object being displayed on your first device
  • See how the value almost instantly updates on the second device as well

And that on it’s own is already an incredibly cool demo!! Another cool fact is that it involves such little code.

Get more development news like this

But there is a small caveat in the scenario above… On both devices, I’m logged in as the same user. What if I want to use different users? We can of course, when we create our Realm, define that User B and User C also have access to that Realm, but that is all too easy and not worthy of an entire blogpost. :-) In the scenario I was developing, I wanted to invite anybody that I would want to connect to my Realm data store, without actually knowing what his or her username is on my Realm Object Server. And I got just the right tool for the job:

OfferPermissionsAsync and AcceptPermissionOfferAsync

When taking a look at the Realm documentation, we see that there is the ability to offer permissions to your Realm. When calling the OfferPermissionsAsync on the user object, we can define which permissions we want to offer on our Realm (who would have thought that…). We don’t define a particular user or anything, because the purpose of this PermissionOffer is that whoever gets and accepts the offer gets the provided permission on the data store.

When calling the above method, we get back a token (a string) from Realm. This token can then be processed by the other user so he can make a connection to the Realm being shared. The second user just needs to pass the token to the AcceptPermissionOfferAsync method which is present on the user object. Look at it like a kind of handshaking that needs to be done. Once this token is processed, we get back the url of the Realm so that we can connect to it. The final piece of the puzzle is getting that token to another user. For this I used the ZXing library to generate a QR code from that token. The other user can then easily, from within our app, scan the code so that we get the token and do our little handshaking.

Show me the code

The inviting side of the story

To create an invite, I’ve built a InvitationHelper class that has a static method CreateInviteAsync.


public static async Task<MyInvitation> CreateInviteAsync(string realmUrl)
{
    var expiresAt = DateTimeOffset.UtcNow.AddDays(7);
    var token = await User.Current.OfferPermissionsAsync(realmUrl, 
        AccessLevel.Write, expiresAt);
    return CreateInvite(token);
}

This method will basically call the OfferPermissionsAsync method on the user object, which will return a token. The CreateInviteAsync will return us a MyInvitation object. This object is just a wrapper around the Token that has been generated by Realm. I’ve made this wrapper class so I could add some metadata to the invitation if I wanted to. No further boilerplate code has to be written, calling the OfferPermissionsAsync method will do all the magic for us in the background!

Finally, on the inviting side of the story, the only thing left to do, is generating a QR code. The QR code will be our MyInvitation object serialized as a JSON string.

To display a QR code, I’ve used the ZXing library. This library makes it a breeze to write and read QR codes (and others). Just install it through NuGet (ZXing.Net.Mobile.Forms) and you’re good to go. On my InvitePage, I put a ZXingBarcodeImageView control like this:


<ZXing:ZXingBarcodeImageView 
                    x:Name="BarCodeView"
                    HorizontalOptions="Fill"
                    VerticalOptions="Fill"
                    HeightRequest="300"
                    WidthRequest="300"
                    Margin="10"
                    BarcodeFormat="QR_CODE" />
                    

In the code-behind of my Invite page, I’ve got a constructor that takes a MyInvitation object. This parameter gets serialized by using Newtonsoft.Json and this serialized content is set as the BarcodeValue of my ZXingBarcodeImageView control.


public InvitePage(MyInvitation invite) 
    : this(Newtonsoft.Json.JsonConvert.SerializeObject(invite))
{ }

public InvitePage(string content)
{
    InitializeComponent();
    BarCodeView.BarcodeOptions.Height = 300;
    BarCodeView.BarcodeOptions.Width = 300;
    BarCodeView.BarcodeValue = content;
}

The invitee side of the story

On this side of the story, we need to scan the QR code generated by the other user, parse it (we know it is an object of type MyInvitation), take the token (and maybe some additional metadata), and pass the token to the AcceptPermissionOfferAsync method of the user object.

First things first: we need to create a new ZXing.Mobile.MobileBarcodeScanner. Once we have this, we can call the Scan method on it which will return the string value of the scanned QR/barcode. We can then deserialize this string to a MyInvitation object.


public static async Task<MyInvitation> ScanInviteAsync()
{
    var scanner = new MobileBarcodeScanner();
    var result = await scanner.Scan();
    if (result != null)
    {
        try
        {
            return JsonConvert.DeserializeObject<MyInvitation>(result.Text);
        }
        catch (Exception)
        {
            //ToDo
        }
    }
    return null;
}

In the static InvitationHelper class that we used earlier, I’ve also added an AcceptInvitationAsync method. From the MyInvitation object, I can get the token and pass it in the AcceptPermissionOfferAsync method of the user object. Again, Realm will do its thing and so the handshaking is done.


public static async Task<Realm> AcceptInvitationAsync(MyInvitation invitation)
{
    var realmUrl = await User.Current.AcceptPermissionOfferAsync(invitation.Token);
    var config = new SyncConfiguration(User.Current, new Uri(realmUrl));
    return await Realm.GetInstanceAsync(config);
}

The result of this method is a string, which is the url to the Realm that is being shared. We can now set up a SyncConfiguration object passing in the user itself and the url to the shared Realm. With this SyncConfiguration object we can create an instance of a Realm object. The resulting Realm object will point to the Realm data store that User A shared.

Both User A and User B can now read from and write to this Realm data store. On both clients, the data is kept in sync in real-time!

Demo

I’ve made a small chat app to demonstrate this technique of sharing a realm by using a QR code. You can find it on my GitHub

Note

When adding the XZing library to you app, make sure you do the following:

On Android, before LoadApplication:

ZXing.Net.Mobile.Forms.Android.Platform.Init();
MobileBarcodeScanner.Initialize(Application);

On iOS, before LoadApplication:

ZXing.Net.Mobile.Forms.iOS.Platform.Init();

and add the following to the Info.plist:

<key>NSCameraUsageDescription</key>
<string>The app would like to use your camera</string>

Next Up: Introducing .NET Core Support for Realm

General link arrow white

About the content

This content has been published here with the express permission of the author.


Pieter Nijs

Pieter is most passionate about mobile and cloud development in combination with DevOps, and because he focuses on the Microsoft stack this translates to technologies and tools like .NET, C#, XAML, Xamarin, UWP, Azure, Visual Studio, TFS, & VSTS. He works as a Senior .NET Consultant and Competence Lead Mobile at Ordina Belgium. Both at work as well as in his spare time he is constantly working and playing with new technologies. He loves to share knowledge, and you can find him speaking at conferences, giving trainings and blogging at Pie Eating Ninjas.

4 design patterns for a RESTless mobile integration »

close