Agenda
Mobile Development Landscape
Why Meteor for Mobile?
How we use Meteor
Five Meteor Patterns to Consider
Meteor 1.0 Cordova
Our goal is to create mobility applications for an
always-on, use from anywhere workforce that increase
productivity in new, unimagined ways and to increase
business performance with applications that are easy
to access, easy to use, and easy to build, test, deploy
and maintain.
Why Meteor for Mobile?
Updates to data are pushed to all clients in real-time
Updates to the application are pushed to clients without a new app install
Cordova is included with Meteor 1.0
Cordova plugins (like Camera, Geolocation, reload-on-resume) are available OOTB
Meteor built on Node.js
Server-side Node.js empowers event driven
programming with NIO and callbacks
Moves away from request/response paradigm to
event-based paradigm using subscriptions
Clients kept up-to-date through SockJS’s
WebSockets emulation
Meteor Subscriptions
Meteor is also built on MongoDB and uses
MiniMongo in-memory DB on the client
The server publishes what it wants to share; the
client filters what it wants to display
Client maintains data without having to round-trip
every time back to the server and server pushes
updates
// On the serverMeteor.publish(“requests”, function(limit) {
var userToken = sessionUserAndToken(this.userId, this.connection.id);var user = userToken.user;
return Requests.find( { $and: [{uid: user.uid},{status: {$nin: [‘approved’, ‘failed’, ‘cancelled’]}},
]}, {sort: { ‘timestamp’: 1, ‘requestedFor’: 1, limit: limit});}
// On the clientMeteor.subscribe(“requests”, Session.get(‘listLimit’), function() {
// Callback function }
Some Context…
Used Sencha Touch originally for Mobile applications
for its rich components
Starting using Node.js for services ExpressJS,
Restify, and Mongoose for interaction with MongoDB
Meteor was a natural fit moving forward given our
past experiences
Mobile Approval Hub
A single mobile application that is used to approve requests from multiple IT systems
A mobile application that doesn’t require app updates or constant reauthentication
Supports push notifications
It must be fast, despite integrating with several IT systems we didn’t control
Application User Stories
As a user, I would like to view requests from multiple
systems
As a user, I would like to approve or deny requests
from multiple systems
As a user, I would like to review the history of actions
I took for past requests
1. Project structure
This is covered in detail here: http://docs.meteor.com/#/full/structuringyourapp
Organize your project by pages
lib/ directories are loaded first which is good for common code and third-party code
Turning off autopublish and insecure packages forces you to organize by client and server
lib/ # common code like collections and utilitieslib/methods.js # Meteor.methods definitionslib/constants.js # constants used in the rest of the code
client/compatibility # legacy libraries that expect to be globalclient/lib/ # code for the client to be loaded firstclient/lib/helpers.js # useful helpers for your client codeclient/body.html # content that goes in the <body> of your HTMLclient/head.html # content for <head> of your HTML: <meta> tagsclient/style.css # some CSS codeclient/<feature>.html # HTML templates related to a certain featureclient/<feature>.js # JavaScript code related to a certain feature
server/lib/permissions.js # sensitive permissions code used by your serverserver/publications.js # Meteor.publish definitions
public/favicon.ico # app icon
settings.json # configuration data to be passed to meteormobile-config.js # define icons and metadata for Android/iOS
2. Templates Refreshing
Break reusable parts into templates
Organize your project by pages
List items must be separate for jQueryMobile Lists to refresh properly
Understand the semantics of create, rendered and destroyed (see http://meteorpedia.com/read/Blaze_Notes)
//HTML<template name=“List”>
{{#each items}}{{>ListItems}}
{{/each}}</template><template name=“ListItems”>
<li class="listitem ui-li-has-thumb”><a id="{{requestId}}" href="#listdetail" data-name="{{additionalProperties}}"
data-transition="slide” class="ui-btn ui-btn-icon-right ui-icon-carrot-r"><img class="avatar" src='{{emppics}}{{uid}}.jpg’
onError="imgError(this,false)" /><p class="requestor">{{requestorInfo.fullName}}</p><p class="description">{{additionalProperties.DESCRIPTION}}</p><p class="money">{{additionalProperties.REQUISITIONTOTAL}}</p>
</a></li>
</template>
// JavaScriptTemplate.ListItems.rendered = function(){
$('#listv').listview('refresh');};
3. Helpers can be
very…well, helpful!
A helper function can be used globally by all
templates to render things the way you’d like
Examples are Dates, Currency, People’s names, etc.
Create helper one time use directly in HTML as an
expression {{[helper]}}
//JavaScriptvar DateFormats = {
short: "DD-MMM-YYYY”, long: "dddd DD.MM.YYYY hh:mm A"};
Template.registerHelper("formatDate", function(datetime, format) {if (moment(datetime).isValid()) {
var f = DateFormats[format],dt = moment(datetime);
if (format === 'long' || format === 'medium') {var localTime = moment.utc(dt).valueOf();return moment(localTime).format(f);
} else {return moment(dt).format(f);
}} else {
return '';}
});
//HTML<p>This request was {{record.status}} on {{formatDate record.lastModified "medium"}}</p>
4. Keeping things up to date
For full records this happens automatically by using
subscriptions
How about fields in records or counts?
Use Tracker.autoRun(callback)
Use Query.observeChanges()
//JavaScriptTracker.autorun(function () {
var conf = Config.findOne();if (conf) {
Session.set("vordelServer", conf.vordelServer);
if (conf.systemAvailability) {systems.forEach(function (system) {
var available = conf.systemAvailability[system];if (available) {
var isDown = available.toUpperCase() === 'OFF' ? true : false;if (isDown) {
$("." + system).addClass('ui-disabled');} else {
$("." + system).removeClass('ui-disabled');}
}});
}}
});
//JavaScriptfunction processCounts(system) {
var user = Meteor.user(),queryObject = getSystemQueryObject(system);
if (user && queryObject) {var query = queryObject.find({$and: [
{approverUid: user.username},{status: {$nin: status_complete}}
]});
query.observeChanges({// Only need to observe changes as it relates to this query, not collectionadded: function(id, user) { updateListCount(system, false);},removed: function(id) { updateListCount(system, true);}
});}else {
return 0;}
}
5. Using Custom OAuth 2.0
AuthenticationUse accounts-base for base Meteor authentication framework
Use Accounts._generateStampedLoginToken() and Accounts._hashStampedToken(stampedToken); to create token stored in user collection
Use Accounts._getLoginToken(this.conn.id) to get the token to refresh OAuth token later
See here for details: http://stackoverflow.com/questions/24273999/how-to-determine-which-session-im-on-for-oauth-reauthentication-in-meteor
Meteor Cordova Pre 1.0
We used Meteor Rider to PhoneGap our app using
the “DOM hijacking” approach since v0.7.x
Meteor hijacks the PhoneGap app’s HTML/CSS/JS,
just pass URL to Meteor Rider config
Allowed us to not only create the Web pieces but
leverage plugins for push notifications and other
useful bits
Getting Started
Cordova supported OOTB since 0.9.2 but much
improved in 1.0
Best reference:
https://github.com/meteor/meteor/wiki/Meteor-
Cordova-Phonegap-integration
Simply run:
meteor add-platform [ios | android]
Customizing the Experience
Add Cordova plugins (public or private) via command line:
meteor add cordova:[email protected]
meteor add cordova:com.qualcomm.qaps.mobile.plugin.email@https://github.qualcomm.com/lsacco/cordova-email/tarball/{GUID}
//JavaScript/Cordova plugin hookcomm = function () {
var errorCallback = function (err) {alert("Native functionality failed with error: " + err);
};
var email = {message: function (email, subject, callback) {
if (typeof device !== 'undefined' && device.platform === "iOS") {cordova.exec(callback, errorCallback, "EmailComposer", "showEmailComposer", [{"toRecipients": [email]}]);
} else {window.open("mailto:" + email + "?subject=" + subject, '_system');
}}
};
return {email: email
};}();//Usagecomm.email.message(“[email protected]”, “Just a test”);
Customizing the Experience
mobile-config.js is where you can set:
App Name, version, id, etc.
Icon and splash screens
Cordova preferences
Use cordova-build-override directory to mirror and customize “native” code
To create build artifacts (IPA/APK) use:meteor build [bundle path] –server [host]
Meteor Cordova vs.
Meteor RiderCustom classes for push notifications are not getting loaded properly (verdict still out)
Does not support x86 optimized Android emulators like Genymotion; ADB takes a LOOOOONG time
Default iOS emulator is a iPhone 4S; more options in XCode
Better initial load experience (only one splash screen)
References
https://www.discovermeteor.com
https://www.meteor.com/blog/
https://github.com/meteor/meteor/wiki/Meteor-
Cordova-Phonegap-integration
http://meteorpedia.com/read/Blaze_Notes
http://stackoverflow.com/search?q=meteor