Trigger.io + Firebase = three native mobile apps, one codebase

Editor's note: Amir Nathoo is Co-Founder & CEO at Trigger.io. He's based in San Francisco.

Introduction to Trigger.io

Trigger.io's mission is to make it simple for web developers to build native mobile apps using languages and tools you're already familiar with. We're in the middle of huge growth in mobile in the number of devices, number of apps, and the time that users are spending interacting with them. Users want to consume content and take actions on the web, mobile web and in apps depending on the context. That creates challenges for developers launching new services or looking to enhance existing ones to take advantage of the mobile shift - there are more platforms and different types of user interaction to support than ever before. Trigger.io improves your productivity when you get started with mobile apps by letting you re-use your web codebases and skills.

Developers love our platform for the fast build / test cycle and large breadth of JavaScript APIs giving you access to native features. After you've launched, our platform let's you iterate faster by enabling you to push updates to your apps faster than the usual app store processes (see Reload). But we only handle one part of the mobile app stack - the client-side. Complex mobile apps need more than that, typically, a back-end data store, push notifications server, analytics and others. Which is why we play nicely with the likes of Parse, Flurry, Firebase, Facebook, Urban Airship and others with native integrations.

To show you how easy it is to create an app using Trigger.io, we put together a short tutorial below.

tl;dr:

  • Download our toolkit
  • Grab the sample code from GitHub
  • Include Firebase in the index.html file
  • Run on both web and mobile using the same codebase

Below:


Trigger.io + Firebase Tutorial

To show you how easy it is to create an app using Trigger.io, we put together a short tutorial below (for Mac users). In it we’re using Trigger.io for the UI and Firebase for the backend to create a fully functional native app for three platforms using one code base. We’ll use a simple demo wine app that I’ve been working on that also includes native UI components. You can see the code for this app on github here, and you can actually install the app on your mobile device via the App Store or Google Play.

Getting started

  1. Install the Trigger.io toolkit from https://trigger.io/forge/toolkit
  2. Start the Toolkit and create an account
  3. Create a new project, titled “Sample Project”
  4. Create a new app, titled “Wine Box” and note the app directory
  5. Open a terminal and navigate to the wine-box directory
  6. Copy your identity.json file away and remove the template contents in the src directory:
    cd src
    mv identity.json ..
    rm -rf *
    rm .forgeignore
  7. Checkout this repository and copy the identity.json file back:
    git clone https://github.com/amirnathoo/Wine-Box .
    cd ..
    mv identity.json src/

Build and test your codebase for both mobile and web

You can do this two ways: through the web interface or through the command line (for more info check out the documentation).
Web interface:




  1. In the Toolkit, click on the app name, navigate to the ‘Forge’ option in the left-hand menu and click the ‘iOS’ button to run it. The first time this will take a minute or so, subsequent incremental builds will be very fast.
  2. You’ll see the full console output while Trigger.io performs the compile and then iPhone emulator will start up in a few seconds.
  3. You can run the web app at the same time, just open toolkit in another browser window and click the “Web” button.

Via the command line:

forge run web
forge run ios

To build and run the Android app, check out our documentation to make sure you’ve set up your environment correctly.

Integrate Firebase

You’ll need to sign-up with Firebase on their website and create a namespace for your app – ‘winebox’ for our example. Once you’ve done that, integrating Firebase is a simple as saving their firebase.js library (already done for you here) and referencing it from the index.html of your Trigger.io app along with other libraries you’ll want to use:

<title>Wine Box</title>
<script src='lib/firebase.js'></script>
<script src="lib/jquery.min.js"></script>

Done!

Just run the app on both web and mobile as you did before. Make sure you have at least one photo in your iOS simulated device (if you don’t have any, just drag some wine photos to the simulated native “Photos” app). Run both the web and iOS apps side by side to see the magic in action:

As you can see Firebase is like Dropbox for JavaScript objects, and makes the syncing part dead-simple without you having to worry about creating your own server-side stack or network connectivity / cacheing on the client-side.

We hope this has inspired you to build mobile and web apps with Trigger.io, using Firebase to power the backend and synch the data. Just download the toolkit to get started!

Any problems at any point? Ask the community on StackOverflow or contact support@trigger.io.


Firebase Integration Details

As part of our initialization code in wine.js we setup the Firebase objects we need and our Backbone collection:

forge.logging.log('... Start initStorage');
//Initialize Firebase
wine.publicFirebase = new Firebase('https://winebox.firebaseio.com/public&#039;);
wine.userFirebase = new Firebase('https://winebox.firebaseio.com/&#039;+wine.user);
wine.photos = new wine.collections.Photos();

In models.js we defined wine.collections.Photos() to be our Backbone collection.

And we’ve created two Firebase objects – one for our public stream and one for the user-specific stream. The Wine Box app is designed to let you take photos of wine labels at restaurants so you can rate the wine you’ve drunk. Within the mobile app you’ll see a list of the wine you’ve personally rated, while there’ll be a public list on the web.

For this purpose we’ll denormalize the data, so when we add new models, we’ll add them to both the public and user-specific object. Here’s what the winebox object will look like in Firebase’s graphical debugger with two users have added a wine object each:

Next we need to initialize our Backbone model so we can show the right list of wine photos and ratings on mobile and web, and listen for changes so the public list on the web updates automatically when a new rating is made in the mobile app.

To do that, we first need to branch our code depending on whether we’re on mobile or the web. Doing that is easy with the forge.is API:

if (forge.is.web()) {

} else { //We must be on mobile }

In the mobile branch, we use Firebase’s once method to read the data snapshot for the user:

wine.userFirebase.once('value', function(snapshot) {
    forge.logging.log('firebase.once triggered');
    $('#loading').remove();
    snapshot.forEach(function(photo) {
        var photomodel = wine.addPhotoFromFirebase(photo);
        if (!photomodel.has('dataurl')) {
            wine.setDataUrl(photomodel.get('url'), photomodel.get('timestamp'));
        }
    });
});

For every object in the user-specific Firebase object, we call our own ‘addPhotoFromFirebase’ method in wine.js to populate our Backbone model.

The way we show the photo on the web is to convert it into a data url on the mobile device and then add it to the Firebase model – in case we didn’t manage to complete that process when the photo was originally taken, you can see us check for, and if necessary, populate the ‘dataurl’ attribute with a call to our ‘setDataUrl’ method in wine.js.

To complete the picture for the mobile app, we need to make sure that if a wine rating is deleted within the app, the appropriate Firebase model is updated so the change can be replicated elsewhere:

wine.photos.on("remove", function(photo) {
    state.get('list').remove(photo.get('timestamp'));
    wine.publicFirebase.child(photo.get('timestamp')).remove();
    wine.userFirebase.child(photo.get('timestamp')).remove();
});

In the web branch, we not only want to populate the public list of wine photos and ratings, but also listen for updates so the list on the web can change dynamically according to user actions in the mobile app. For that, we use Firebase’s on method:

wine.publicFirebase.on('childadded', function(photo) {
    forge.logging.log('firebase on childadded triggered');
    $('#loading').remove();
    wine.addPhotoFromFirebase(photo);
});
wine.publicFirebase.on('childremoved', function(photo) {
    forge.logging.log('firebase on childremoved triggered');
    forge.logging.log('removing from list with timestamp: '+photo.val().timestamp);
    state.get('list').remove(photo.val().timestamp);
});
wine.publicFirebase.on('childchanged', function(photo) {
    forge.logging.log('firebase on childchanged triggered');
    forge.logging.log('updating image with timestamp: '+photo.val().timestamp);
    forge.logging.log('using dataurl: '+photo.val().dataurl);
    wine.photos.where({timestamp: photo.val().timestamp})[0].set("dataurl", photo.val().dataurl);
    state.get('list').addImage(photo.val());
});

This code ensures that whenever an item is added, deleted or updated within the mobile app, the change is replicated in the model that we use for our list of wine photos and ratings on the web. It’s as simple as that.