Using PouchDB for PhoneGap/Cordova apps

Chris Kelley

chrisekelley

on github and twitter.

UBridge: SMS -> Couch on Android in Uganda

UBridge diagram

UBridge

Hosting Criteria

Hosting

This is an HTML5 App Using

Mobile Platform & Devices

Why PouchDB?

Development Approach

2 projects

Building the Android app

build.sh

grunt cordova-build
adb uninstall org.rti.olutindo_app
adb install -r platforms/android/bin/Olutindo-debug.apk

Transitioning TouchDB to PouchDB

Converting CouchDB Views

Created pouchdb_views.js and named each query:

var byIncidentSorted = function(doc) {
  if (doc.formId === "incident") {
    emit(doc.lastModified, doc);
  }
}
var bySearchKeywords = function(doc) {
  if(doc.phone) {
    emit(doc.phone, doc);
  }
}

PouchDB Query Example


searchResults.fetch(
  {fetch: 'query',
    options: {
        query: {
            fun:bySearchKeywords,
            key:searchTerm
        }
    },
    success: function(collection, response, options) {
        FORMY.Incidents = searchResults;
        var page = new Page();
        var Home = new HomeView(
            {model: page, el: $("#homePageView")});
    }}
);

PouchDB Query Examples

Fetch

var record = new Incident({_id: incidentId});
record.fetch( {
  success: function(model){
  // do something
    });
  }
});

Save

var record = new Record(formData);
record.save();

Does it really have IndexedDB?


var ua = navigator.userAgent;
var is412 = ua.indexOf("4.1.2");
var isGTP6200 = ua.indexOf("GT-P6200");
if ((is412) && (isGTP6200))
{
  Backbone.sync = BackbonePouch.sync({
    db: PouchDB('websql://troubletickets')
  });
} else {
  Backbone.sync = BackbonePouch.sync({
    db: PouchDB('troubletickets')
  });
}

Pagination

Use endkey instead of startkey for descending order.


var opts = {
  query: {
    fun: {map: byIncidentSorted}
    , descending:true
    , endkey:parseInt(endkey)
    , limit:limit
  }
}

Replication

CouchDB

var credentials = account.username + ":" + account.password;
couch = "http://" + credentials + "@192.168.1.60:5984/" + couchdb + "/";
var opts = {continuous: true,
  withCredentials:true,
  auth: {username:account.username, password:account.password},
  complete: onComplete,
  timeout: 60000};
Backbone.sync.defaults.db.replicate.to(couch, opts, ReplicationErrorLog);
Backbone.sync.defaults.db.replicate.from(couch, opts, ReplicationErrorLog);

Developing with PouchDB

Puton


Development Issue

CORS: Cross-origin resource sharing

(bypass same origin security policy)

Where to enable CORS?

Cloudant needs CORS.

CORS solution:

Using express for dev + request to reverse proxy replication

app.js for express:

var forward = require('./forward.js');
//typical static express config
app.use(express.static(__dirname + '../../www'));
var target_url = "cloudant.com/troubletickets"
app.use(forward(/\/troubletickets\/(.*)/, target_url));

CORS solution:

Using express + request to reverse proxy replication

forward.js:

if(req.url.match(pattern)){
  var db_path = req.url.match(pattern)[1], parts = db_path.split("/");
  var subdomain = parts[0], credentials = parts[1];
  var query = parts[2];
  var db_url = "https://" + credentials + "@" + subdomain
   + "." + host + "/" + query
  req.pipe(request[req.method.toLowerCase()](db_url)).pipe(res);
}else{
  next();
}

CORS solution:

Replication

var remoteCouch = "http://localhost:3000/troubletickets/"
+ subdomain + "/" + credentials;
if (navigator.userAgent.match(/(iPhone|Android)/)) {
  remoteCouch = "https://" + credentials + "@" + subdomain
  + ".cloudant.com/troubletickets/";
}
Backbone.sync.defaults.db.replicate.to(couch, opts, ReplicationErrorLog);
Backbone.sync.defaults.db.replicate.from(couch, opts, ReplicationErrorLog);

Using Cordova

Do enough plugins support Cordova 3.0?

Plugins i'm using

Adding a plugin

cordova plugin add https://github.com/urbanairship/phonegap-ua-push.git

Handling plugins

Load Cordova .js in Cordova only.

if (navigator.useragent.match(/(iPhone|iPod|iPad|Android|BlackBerry|IEMobile)/)) {
  loadScript('cordova.js');
  loadScript('version.js');
  loadScript('sms.js');
  loadScript('js/PushNotification.js');
  }

Handling plugins

Find plugin instance in plugin.xml
<js-module src="www/sms.js" name="Sms">
  <clobbers target="window.sms" />
</js-module>

Testing for plugin instance
if (typeof window.sms != 'undefined') {
    // code
}

Notifications using PushNotification

Urban Airship

Lower data costs: switch from continuous replication by using notifications

Thanks!