Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Synchronizing Images Between Android and iOS With NativeScript, Angular, and Couchbase

DZone's Guide to

Synchronizing Images Between Android and iOS With NativeScript, Angular, and Couchbase

Learn to sync images between iOS and Android mobile devices and platforms with Couchbase Mobile, using NativeScript and Angular.

· Mobile Zone
Free Resource

Download this comprehensive Mobile Testing Reference Guide to help prioritize which mobile devices and OSs to test against, brought to you in partnership with Sauce Labs.

A few weeks ago I had written a guide that demonstrated saving captured images to Couchbase Lite as base64 encoded string data in a NativeScript with Angular mobile application. While the previous guide worked for both Android and iOS, the data was localized to the device. What if you wanted to synchronize the images between devices or even store them in the cloud?

We’re going to see how to use Couchbase Mobile to synchronize image data between devices and platforms in a NativeScript with Angular application.

Going forward you should note that this is part two in the series.  This means that if you haven’t already followed the previous tutorial and gotten a working version of the project, you should put this tutorial on hold. Start with the guide, Save Captured Images in a NativeScript Angular Application to Couchbase, then work your way into synchronizing the images.

The above animated image will give you a rough idea of what we’re after.  We want to be able to synchronize the saved images between Android and iOS using Sync Gateway and optionally Couchbase Server.

The Requirements

The prerequisites for this guide are similar to what was found in the previous.  You’ll need the following:

  • NativeScript CLI.
  • Android SDK for Android or Xcode for iOS.
  • Couchbase Sync Gateway.
  • Couchbase Server (optional).

You’ll notice that Sync Gateway and optionally Couchbase Server are the new requirements of this guide in the series.  We’ll need these for synchronization to actually happen.  If you’re unfamiliar, Sync Gateway is the synchronization middleware and Couchbase Server is the remote database server.

Configuring Sync Gateway for Replication

To use Sync Gateway we’ll need to define a configuration as to how synchronization happens and things like that.

Create a sync-gateway-config.json file somewhere on your computer that contains the following information:

{
    "log":["CRUD+", "REST+", "Changes+", "Attach+"],
    "databases": {
        "image-database": {
            "server":"walrus:data",
            "sync":`
                function (doc) {
                    channel (doc.channels);
                }
            `,
            "users": {
                "GUEST": {
                    "disabled": false,
                    "admin_channels": ["*"]
                }
            }
        }
    }
}

In the above configuration file we are saving everything to walrus:data which is an in-memory solution rather than persisting it to Couchbase Server.  The remote database is called image-database, but it doesn’t have to match what we have in our mobile application code.

For simplicity, everyone will be able to read and write data in the same channel as a guest.

To run Sync Gateway, execute the following:

/path/to/sync_gateway /path/to/sync-gateway-config.json

You should be able to access Sync Gateway from your web browser at http://localhost:4984/_admin/ and view everything that is being synchronized, often referred to as replicated.

Adding the Logic for Synchronizing Image Data

The actual code involved towards getting replication working in our NativeScript with Angular application is minimal.

Open the project’s app/app.component.ts file and include the following TypeScript code:

import { Component, OnInit, NgZone } from "@angular/core";
import { Couchbase } from "nativescript-couchbase";
import * as Camera from "camera";
import * as ImageSource from "image-source";

@Component({
    selector: "ns-app",
    templateUrl: "app.component.html",
})
export class AppComponent implements OnInit {

    private database: any;
    private pushReplicator: any;
    private pullReplicator: any;
    public images: Array<any>;

    public constructor(private zone: NgZone) {
        this.database = new Couchbase("image-database");
        this.database.createView("images", "1", function(document, emitter) {
            if(document.type && document.type == "image") {
                emitter.emit(document._id, document);
            }
        });
        this.pushReplicator = this.database.createPushReplication("http://192.168.57.1:4984/image-database");
        this.pullReplicator = this.database.createPullReplication("http://192.168.57.1:4984/image-database");
        this.pushReplicator.setContinuous(true);
        this.pullReplicator.setContinuous(true);
        this.images = [];
    }

    public ngOnInit() {
        this.pushReplicator.start();
        this.pullReplicator.start();
        this.database.addDatabaseChangeListener(changes => {
            for(let i = 0; i < changes.length; i++) {
                this.zone.run(() => {
                    let image = ImageSource.fromBase64(this.database.getDocument(changes[i].getDocumentId()).image);
                    this.images.push(image);
                });
            }
        });
        let rows = this.database.executeQuery("images");
        for(let i = 0; i < rows.length; i++) {
            this.images.push(ImageSource.fromBase64(rows[i].image));
        }
    }

    public capture() {
        Camera.takePicture({ width: 300, height: 300, keepAspectRatio: true, saveToGallery: false }).then(picture => {
            let base64 = picture.toBase64String("png", 70);
            this.database.createDocument({
                "type": "image",
                "image": base64,
                "timestamp": (new Date()).getTime()
            });
        }, error => {
            console.dump(error);
        });
    }

}

The above code includes everything from the first part of the series as well as this part of the series.  We’re going to break down only what has been added in regards to replication.

In the constructor method we define where we are going to push data to and where we are going to pull data from.

this.pushReplicator = this.database.createPushReplication("http://192.168.57.1:4984/image-database");
this.pullReplicator = this.database.createPullReplication("http://192.168.57.1:4984/image-database");
this.pushReplicator.setContinuous(true);
this.pullReplicator.setContinuous(true);

This is to be done continuously for as long as the application is open. Make sure you use the correct host or IP address for Sync Gateway. If you’re using Genymotion like I am, localhost will not work. You’ll have to figure out the correct IP addresses.

In the ngOnInit method we start the replication process and configure a listener.

this.pushReplicator.start();
this.pullReplicator.start();
this.database.addDatabaseChangeListener(changes => {
    for(let i = 0; i < changes.length; i++) {
        this.zone.run(() => {
            let image = ImageSource.fromBase64(this.database.getDocument(changes[i].getDocumentId()).image);
            this.images.push(image);
        });
    }
});

Any time there is a change in the database we will loop through them and load the base64 data. This example is simple so there are no updates or deletions of images. If this were the case, our listener would be a little more complex in logic. The reason we are using an Angular NgZone is that the listener operates on a different thread. By zoning, we can take the data and make sure the UI updates correctly.

That’s all we had to do to get the images synchronizing between device and server. Easy, right?

You just saw how to synchronize image data between devices and platforms using NativeScript, Angular, and Couchbase. This was a followup to the previous tutorial I wrote called, Save Captured Images in a NativeScript Angular Application to Couchbase, where we got the initial application up and running. In case you’d rather not store your images in the database, you might consider creating an API that uses an object storage like Minio or Amazon S3.  I’ve written a tutorial on creating an API that saves to Minio that might help.

Analysts agree that a mix of emulators/simulators and real devices are necessary to optimize your mobile app testing - learn more in this white paper, brought to you in partnership with Sauce Labs.

Topics:
mobile ,nativescript ,angular ,couchbase ,android ,ios

Published at DZone with permission of Nic Raboy, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}