DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
  1. DZone
  2. Coding
  3. JavaScript
  4. Getting Started with React Native Android and Couchbase Lite

Getting Started with React Native Android and Couchbase Lite

Wondering how to use React Native Android with Couchbase Lite? Here's your comprehensive starter guide.

James Nocentini user avatar by
James Nocentini
·
Nov. 13, 15 · Tutorial
Like (2)
Save
Tweet
Share
4.75K Views

Join the DZone community and get the full member experience.

Join For Free

react native enables you to build android applications that look and feel native with only javascript. in this instance, react native takes care of managing ui state and synchronizing it with the models. and luckily for us, we can use couchbase lite to add sync and persistence to a react native app. in this tutorial, you will learn how to build a simple application to save documents and replicate them to sync gateway . here are the core concepts you will learn:

  1. create a basic project with couchbase lite android and couchbase lite java listener
  2. integrating react native in your project
  3. adding models and ui components with javascript
  4. setting up couchbase sync gateway

here’s a sneak peek of what you are going to build:

you can download the completed project from github .

prerequisites

  • node.js 4.0 or higher
  • android studio and an emulator

getting started

in this section, you will create a new android studio project from scratch and integrate react native to it.

new android studio project

before you start writing some javascript you need to create a new android studio project with all the dependencies. open android studio and from the welcome screen select new project . in the new project window, enter todolite reactnative android for the application name and todolite-reactnative-android for the folder name:

set the minimum required sdk to api 16: android 4.1 or later and use the currently recommended android api. after you fill in the fields, the new project window should look something like this:

click next, and choose the blank activity template:

click finish and you should see the following in the project navigator:

bundling dependencies

expand the app folder, and then open the build.gradle file. make sure you open the one located in the app folder (also called the module) and add the following in the android section:

// workaround for "duplicate files during packaging of apk" issue
// see https://groups.google.com/d/msg/adt-dev/bl5rc4szpzg/wc8cyltwuiej
packagingoptions {
    exclude 'meta-inf/asl2.0'
    exclude 'meta-inf/license'
    exclude 'meta-inf/notice'
}

next, open build.gradle at the root (also refererred to as the project level gradle file) and add a reference to the couchbase maven repository:

allprojects {
    repositories {
        jcenter()
        maven {
            url "http://files.couchbase.com/maven2/"
        }
    }
}

now, add the following lines to the top-level dependencies section:

dependencies {
    compile filetree(dir: 'libs', include: ['*.jar'])
    testcompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:23.1.0'

    compile 'com.couchbase.lite:couchbase-lite-android:1.1.0'
    compile 'com.couchbase.lite:couchbase-lite-java-listener:1.1.0'
    compile 'com.couchbase.lite:couchbase-lite-java-javascript:1.1.0'
    compile 'com.facebook.react:react-native:0.13.0'
}

in the android studio tool bar, click sync project with gradle files.

setting up couchbase lite and the listener

open androidmanifest.xml located in app/src/main and add the permissions:

<uses-permission android:name="android.permission.internet" />
<uses-permission android:name="android.permission.access_network_state" />
<uses-permission android:name="android.permission.access_network_state"/>

the react native android activity

you need to add some native code in order to start the react native runtime and get it to render something. replace the content of mainactivity.java with the following and we’ll explain what is going on next:

public class mainactivity extends activity implements defaulthardwarebackbtnhandler {
    private reactrootview mreactrootview;
    private reactinstancemanager mreactinstancemanager;

    private final string tag = "todolite";
    private static final int default_listen_port = 5984;
    private int listenport;
    private credentials allowedcredentials;

    @override
    protected void oncreate(bundle savedinstancestate) {
        super.oncreate(savedinstancestate);

        log.d(tag, "oncreate method called");

        // 1
        mreactrootview = new reactrootview(this);
        mreactinstancemanager = reactinstancemanager.builder()
                .setapplication(getapplication())
                .setbundleassetname("index.android.bundle")
                .setjsmainmodulename("index.android")
                .addpackage(new mainreactpackage())
                .setusedevelopersupport(buildconfig.debug)
                .setinitiallifecyclestate(lifecyclestate.resumed)
                .build();
        mreactrootview.startreactapplication(mreactinstancemanager, "todolite-reactnative-android", null);

        setcontentview(mreactrootview);
        initcblite();
    }

    private void initcblite() {
        try {

            // 2
            allowedcredentials = new credentials("", "");

            // 3
            view.setcompiler(new javascriptviewcompiler());

            // 4
            androidcontext context = new androidcontext(this);
            manager.enablelogging(log.tag, log.verbose);
            manager.enablelogging(log.tag_sync, log.verbose);
            manager.enablelogging(log.tag_query, log.verbose);
            manager.enablelogging(log.tag_view, log.verbose);
            manager.enablelogging(log.tag_change_tracker, log.verbose);
            manager.enablelogging(log.tag_blob_store, log.verbose);
            manager.enablelogging(log.tag_database, log.verbose);
            manager.enablelogging(log.tag_listener, log.verbose);
            manager.enablelogging(log.tag_multi_stream_writer, log.verbose);
            manager.enablelogging(log.tag_remote_request, log.verbose);
            manager.enablelogging(log.tag_router, log.verbose);
            manager manager = new manager(context, manager.default_options);

            // 5
            listenport = startcbllistener(default_listen_port, manager, allowedcredentials);

            log.i(tag, "initcblite() completed successfully with: " + string.format(
                    "http://%s:%s@localhost:%d/",
                    allowedcredentials.getlogin(),
                    allowedcredentials.getpassword(),
                    listenport));

        } catch (final exception e) {
            e.printstacktrace();
        }

    }

    private int startcbllistener(int listenport, manager manager, credentials allowedcredentials) {
        litelistener listener = new litelistener(manager, listenport, allowedcredentials);
        int boundport = listener.getlistenport();
        thread thread = new thread(listener);
        thread.start();
        return boundport;
    }

    @override
    protected void onpause() {
        super.onpause();
        if (mreactinstancemanager != null) {
            mreactinstancemanager.onpause();
        }
    }

    @override
    protected void onresume() {
        super.onresume();
        if (mreactinstancemanager != null) {
            mreactinstancemanager.onresume(this);
        }
    }


    @override
    public void onbackpressed() {
        if (mreactinstancemanager != null) {
            mreactinstancemanager.onbackpressed();
        } else {
            super.onbackpressed();
        }
    }

    @override
    public boolean onkeyup(int keycode, keyevent event) {
        if (keycode == keyevent.keycode_menu && mreactinstancemanager != null) {
            mreactinstancemanager.showdevoptionsdialog();
            return true;
        }
        return super.onkeyup(keycode, event);
    }

    @override
    public void invokedefaultonbackpressed() {
        super.onbackpressed();
    }
}

a few things are happening here:

  1. you create an activity that creates a reactrootview , starts a react application inside it and sets it as the main content view. next, you’re calling the initcblite method which does a few things.
  2. here you define an empty name and password to be used by the listener. this means that in theory, anyone could access your database. this is ok for this tutorial but in production you’d replace the line with new credentials() .
  3. plug in the component to compile the javascript views. we’re not going to use couchbase views in this tutorial just yet but it might come in handy.
  4. instantiate the manager and enable logging.
  5. start the couchbase listener passing in the port to listen on, the manager instance and secure credentials.

that’s all for the android part, now you can turn your attention to javascript!

javascript land

in your project’s root folder, run:

$ npm init
$ npm install --save react-native
$ curl -o .flowconfig https://raw.githubusercontent.com/facebook/react-native/master/.flowconfig

this creates a node module for your app and adds the react-native npm dependency. now open the newly created package.json file and add this line inside of the scripts field:

"start": "node_modules/react-native/packager/packager.sh"

hello world

copy & paste the following code to a new index.android.js file in your root folder:

/**
 * sample react native app
 * https://github.com/facebook/react-native
 */
'use strict';

var react = require('react-native');
var home = require('./app/components/home');
var {
  appregistry,
  stylesheet,
  text,
  view,
  toolbarandroid
} = react;


var styles = stylesheet.create({
  container: {
    flex: 1,
    backgroundcolor: '#111111'
  },
  toolbar: {
    backgroundcolor: '#e9eaed',
    height: 56,
  }
});


var todolite = react.createclass({
  render: function() {
    return (
      <view style={styles.container}>
        <toolbarandroid
          title="todolite reactnative android"
          style={styles.toolbar}>
        </toolbarandroid>
        <home/>
      </view>
    );
  }
});

appregistry.registercomponent('todolite-reactnative-android', () => todolite);

build and run!

to run your app, you first need to start the development server. to do this, simply run the following command in your root folder:

npm start

note: at the time of this writing, you may need to run brew update && brew reinstall watchman to update watchman if you get the error error building depdendencygraph: typeerror: cannot read property 'root' of null .

now build and run your android app in a new terminal tab:

./gradlew installdebug

open it in the android simulator and you will see the following:

well done on getting the development environment up and running! react native includes great features such live reload which make it much easier to iterate on the ui of the application, but first you must define the models and methods to persist documents to the couchbase lite database.

a todo application

a simple api

create a new file app/utils/api.js and add the following:

var api = {

  // 1
  localdatabaseurl: 'http://localhost:5984',

  // 2
  remotedatabaseurl: 'http://localhost:4984',

  // 3
  savetodo(title){
    return fetch(this.localdatabaseurl + '/todos', {
      method: 'post',
      headers: {
        'content-type': 'application/json'
      },
      body: json.stringify({
        type: 'list',
        title: title
      })
    }).then((res) => res.json());
  },

  // 4
  gettodos(){
    return fetch(this.localdatabaseurl + '/todos/_all_docs?include_docs=true').then((response) => {
      if (response.status !== 200) {
        return fetch(this.localdatabaseurl + '/todos', {
          method: 'put',
          headers: {
            'accept': 'application/json',
            'content-type': 'application/json'
          },
          body: json.stringify({ok: true})
        }).then((res) => res.json());
      }
      return response.json();
    })
  },

  // 5
  startsync(){
    return fetch(this.localdatabaseurl + '/_replicate', {
      method: 'post',
      headers: {
        'content-type': 'application/json'
      },
      body: json.stringify({
        source: 'todos',
        target: this.remotedatabaseurl + '/todos',
        continuous: true
      })
    }).then((res) => res.json());
  }

};

module.exports = api;
  1. you declare the endpoint the couchbase listener is running on.
  2. the remote database is sync gateway in this case. this would be replaced with your sync gateway production instance.
  3. the method to persist a task document.
  4. here, you’re getting all the documents from couchbase lite.
  5. start a push replication from the couchbase lite database to sync gateway. there could equally be a pull replication as well.

with a basic api in place, you can now turn your attention to building the ui.

building the ui

create a new file in app/components/home.js with the following:

var react = require('react-native');
var api = require('./../utils/api');

var {
  text,
  view,
  stylesheet,
  scrollview,
  textinput,
  touchableopacity
  } = react;

var styles = stylesheet.create({
    container: {
        flex: 1
    },
    buttontext: {
        fontsize: 18,
        color: 'white',
        alignself: 'center'
    },
    rowcontainer: {
        padding: 10
    },
    rowtitle: {
        color: '#48bbec',
        fontsize: 16
    },
    rowcontent: {
        fontsize: 19
    },

    maincontainer: {
        flex: 1,
        padding: 30,
        margintop: 65,
        flexdirection: 'column',
        justifycontent: 'center',
        backgroundcolor: '#48bbec'
    },
    searchinput: {
        height: 50,
        padding: 4,
        marginright: 5,
        fontsize: 23,
        borderwidth: 1,
        bordercolor: 'white',
        borderradius: 8,
        color: 'white',
        margin: 5
    },
    buttontext: {
        fontsize: 18,
        color: '#111',
        alignself: 'center'
    },
    button: {
        height: 45,
        flexdirection: 'row',
        backgroundcolor: 'white',
        bordercolor: 'white',
        borderwidth: 1,
        borderradius: 8,
        marginbottom: 10,
        margintop: 10,
        alignself: 'stretch',
        justifycontent: 'center'
    },
});

class home extends react.component {
    constructor(props) {
        super(props);
        this.state = {
            newtodo: '',
            todos: []
        };
    }
    componentwillmount() {
        api.gettodos()
          .then((res) => {
              var todos = res.rows.map(function (row) {
                  return row.doc;
              });
              this.setstate({
                  todos: todos
              });
          });
    }
    handletodochange(event) {
        this.setstate({
            newtodo: event.nativeevent.text
        });
    }
    handlesave() {
        api.savetodo(this.state.newtodo)
        .then((res) => {
              api.gettodos()
                .then((res) => {
                    var todos = res.rows.map(function (row) {
                        return row.doc;
                    });
                    this.refs.inputtext.value = '';
                    this.setstate({
                        todos: todos,
                        newtodo: ''
                    });
                });
          });
    }
    handlesync() {
        api.startsync()
          .then(function(res) {
              console.log(res);
          });
    }
    render() {
        var lists = this.state.todos.map((item, index) => {
            return (
              <view key={index}>
                  <view style={styles.rowcontainer}>
                      <text style={styles.rowcontent}> {item.title} </text>
                  </view>
              </view>
            );
        });
        return (
          <view style={styles.maincontainer}>
              <textinput
                ref='inputtext'
                value={this.state.newtodo}
                onchange={this.handletodochange.bind(this)}
                style={styles.searchinput}/>
              <touchableopacity onpress={this.handlesave.bind(this)} style={styles.button}>
                  <text style={styles.buttontext}>save</text>
              </touchableopacity>
              <touchableopacity onpress={this.handlesync.bind(this)} style={styles.button}>
                  <text style={styles.buttontext}>sync</text>
              </touchableopacity>
              <scrollview style={styles.container}>
                  {lists}
              </scrollview>
          </view>
        );
    }
}

home.proptypes = {
    lists: react.proptypes.array.isrequired
};

module.exports = home;

don’t get intimidated by the length of this code snippet. all we’re doing here is declaring styles and using some built-in react native ui components to display a text input, buttons and text labels. you can find the list of built-in ui components here .

updating the root component

the final step before you can see your great work in action is to update index.android.js to load the home component. below the require statement to import react-native , add the following:

var home = require('./app/components/home');

next, replace the return value of the render method with <home/> . use the ⌘ + m shortcut in genymotion to reload the javascript and you should see a bright blue screen. that’s good news!

replications with couchbase sync gateway

download sync gateway from the link below and unzip the file:

http://www.couchbase.com/nosql-databases/downloads

in a new file named sync-gateway-config.json , paste the following:

{
  "log": ["*"],
  "databases": {
    "todos": {
      "server": "walrus:",
      "users": { "guest": { "disabled": false, "admin_channels": ["*"] } }
    }
  }
}

and run sync gateway with this config file:

~/downloads/couchbase-sync-gateway/bin/sync_gateway /path/to/project/sync-gateway-config.json

to make the sync gateway endpoint reachable inside of the android vm emulator, you need to enable a port from the host to the vm. in terminal, run the following:

adb reverse tcp:4984 tcp:4984

open the admin ui to monitor the documents that were saved to sync gateway:

http://localhost:4985/_admin/

try adding more task documents and notice how they get pushed to sync gateway automatically.

where to go from here

congratulations! you’ve built your first react native android + couchbase lite application. you’re now ready to add more components such as the following:

  1. couchbase lite views to write custom queries
  2. user authentication in a replication
  3. continuously deploying the sync gateway configuration file and other components

watch out for a tutorial on debugging your react native android + couchbase lite application using charles and genymotion.

feel free to share your feedback, findings or ask any questions in the comments below or in the forums. talk to you soon!

React Native Android (robot) React (JavaScript library)

Published at DZone with permission of James Nocentini, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • How To Create and Edit Excel XLSX Documents in Java
  • Microservices Discovery With Eureka
  • Real-Time Stream Processing With Hazelcast and StreamNative
  • Express Hibernate Queries as Type-Safe Java Streams

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: