Offline your data with React-Native applications

In a previous post, I mentioned how we are leveraging ReactJS to create state-of-the-art web applications. We are now moving a step forward by also leveraging its sister technology, React-Native, to create portable, yet native, mobile applications. With all the benefits of Darwino, which includes a local JSON store that replicates for the best offline experience, and all the other services provided by Darwino!

To make this as easy as possible, we are providing a simple service based API, that can be called from any native language (Java, Objective-C, Swift).

1- Darwino service API

The API is basically made of one class, exposed bellow in pseudo code:

class DarwinoApis {
  Object fetch(url, params, headers, content)

The fetch method calls the service identified by the URL and associated parameters, and returns the result. Behind the hood, such the API call will be either translated to a remote HTTP service call (online mode), or to a local API call (offline mode). This is done transparently by a dispatcher, so the developer does not have to worry about the current mode. It just works! This API can be called from *any* native application, regardless of the library/framework it uses.

This shows the beauty of the Darwino architecture: the services are all written independently from the HTTP stack, and thus can be executed locally without the need of HTTP calls. It makes them truly available offline, while providing the best possible performance as it also avoids the data serialization/deserialization needed by the HTTP transport.

Here is a basic architecture picture:

2- ReactNative integration

As the API is exposed using the platform native languages, it is easy to bridge it with ReactNative. Moreover, the bridge enforces the use of promises, thus enabling the new aync & await capability for the best developer experience.

Here is, for example, how to retrieve the number of documents from a database, regardless if it is local or remote:

async databaseCount() {     let url = ["$darwino-jstore","databases",this.getDatabase(),"documentscount"]     let count = await darwinoApis.fetch(url);     this.println("This database contains {0} documents",count);
Easy, isn't it?

Triggering the database replication isn't more difficult, see:

let result = await apis.replicate(this.getDatabase(),options); this.println("{0}",result);

3- Darwino API distribution

The APIs is provided as a library to be added to any existing application. On Android, it is a maven artifact that you can reference from your gradle build file. On iOS, it is a Cocoa framework that you can add to your XCode project. Just add these dependencies and you're ready to go!



4- Under the hood

Wait, Darwino is Java based, so how can we provide a native Objective-C or Swift API? How can we get all the Darwino services, built-in and customs, run natively on any device? As the goal is to have one single Java source code to ensure the consistency between all the platforms, so how is is exposed as an Objective-C API?

The magic comes from J2OBJC. Right from the beginning, we have been very careful to write "portable" Java, meaning Java that can be compiled or transpiled to many different environments (JRE, Dalvik/Art, RoboVM, Multi-OS Engine...). As J2OBJC made a lot of progress these past years, it became easy to get our code transpiled to J2OBJC. The result is a tiny, efficient, native Objective-C library while sharing the same Java source code.
With the potential to target other platforms in the future, like .NET: what about having your Domino data replicated natively to .NET? :-)