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.
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>
About the content
This content has been published here with the express permission of the author.