What they didn't tell you about Cordova! I started building hybrid apps and you won't believe what happened next!!
Raymond Camden! Developer Advocate for IBM! LoopBack, OpenWhisk, Bluemix, Cordova/ PhoneGap, Node, and web stuff in general! Blogging at raymondcamden.com! Tweeting at @raymondcamden!
Hybrid Dev is Easy!
Decent Hybrid Dev?!
https://www.flickr.com/photos/motoyen/3763218863!
Our Tools! Offline Detection/Support! Client-Side Storage! Internationalization! UI/UX! Performance! Etc.!
Before we begin!
HTML, JS, CSS! That web stuff it s kind of important! Know everything!! Mozilla Developer Network (developer.mozilla.org)! CanIUse (caniuse.com)!
Repeat After Me! (no - seriously)!
You must use dev tools! Period!
Offline - it's not just for breakfast anymore!
The Network is Evil! Your app runs on the device - it doesn't matter whether you're online or not! Your app may start in one state - and enter another! You may be online, but in a really, really crappy manner! You may be online, but behind a wifi captive portal!
What to worry about...! Am I online?! How well am I online?! How much data do I need to transfer?! Can I get by with part of it?!
Oh yeah...! What if your server is offline?! What if your server is online but returning crap?! What if your third party server - ditto...!
Basically...!
What do you do?! Banking apps! Weather apps! Social Media/IM apps!
Code time!! network-information! detects type (how well?)! detects changes!
Demos!
A Place for Your Stuff!
Client-Side Storage! A great way to handle offline! A great way to boost performance!
Types of Storage! Cookies! WebStorage! WebSQL! IndexedDB! File System! SQLite!
Cookies! Yes - seriously! Just FYI! MDN Library - https://developer.mozilla.org/en-us/docs/web/api/ Document/cookie/Simple_document.cookie_framework!
WebStorage! LocalStorage/SessionStorage! Super easy!! ios 8+ kills it though (cuz - ios)! Tips: Use for caching - but assume it won't persist!
WebSQL! Dead spec :(! But guess what - still works (http://caniuse.com/#feat=sql-storage)! But use SQLite instead!
IndexedDB! The future of web storage!! Easy as rocket science!! Really, really, really, really bad ios 9 support (fixed in 10)!
File System! CRUD for the File System! You can do everything! It works!
SQLite! Just works!! (As long as you know SQL ;)! cordova-sqlite-storage!
Examples!
WebStorage!
if(window.localstorage) { var numhits = localstorage.getitem("numhits"); if(!numhits) numhits=0; else numhits = parseint(numhits, 10); numhits++; localstorage.setitem("numhits",numhits); $("#resultdiv").text("you have visited this site "+numhits +" times."); }
IndexedDB!
var openrequest = indexeddb.open("ora_idb1",1); openrequest.onupgradeneeded = function(e) { var thisdb = e.target.result; console.log("running onupgradeneeded"); if(!thisdb.objectstorenames.contains("people")) { var peopleos = thisdb.createobjectstore("people", {keypath: "email"}); } }
var transaction = db.transaction(["people"],"readwrite"); //Ask for the objectstore var store = transaction.objectstore("people"); //Define a person var person = { name:name, email:email, created:new Date().getTime() } //Perform the add var request = store.add(person); request.onerror = function(e) { console.log("error",e.target.error.name); //some type of error handler } request.onsuccess = function(e) { console.log("woot! Did it"); }
WebSQL!
db = window.opendatabase("notestrap", "1.0", "Note App", 5*1024*1024); //Handle initial creation and then load up the notes db.transaction(function(tx) { tx.executesql("create table if not exists notes(id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT, body TEXT, updated DATE)"); }, dberror,function(tx) { getnotes(); });
function getnotes(search) { db.readtransaction(function(tx) { if(!search) { tx.executesql("select id,title,body,updated from notes order by updated desc", [], displaynotes); } else { var fuzzy = "%" + search + "%"; tx.executesql("select id,title,body,updated from notes where title like? or body like? order by updated desc", [fuzzy,fuzzy], displaynotes); } }, dberror); }
File System!
"Use the Library, Luke!"! Lockr (LocalStorage only)! Dexie (IDB)! localforage! pouchdb (syncs!)!
Advertisement! Book and video available at raymondcamden.com!
Spoiler...!
But wait...! They speak a different language (that's cool)! They use a different unit of measurement (that's mostly cool too)! "NASA lost a $125 million Mars orbiter because a Lockheed Martin engineering team used English units of measurement while the agency's team used the more conventional metric system for a key spacecraft operation..." (oh crap)! They write numbers differently (that's just insane)!
Examples:! 1,000,000.99! 1.000.000,99! 1 000 000,99!
4/8/2016!
Is it...! April?! August?! It's my birthday so you're both right!!
Issues! Formatting:! Numbers change! Currencies change! Dates change! UI changes:! Buttons! Labels! Etc!
Solutions (Formatting)! https://www.npmjs.com/package/cordova-plugin-globalization! cordova plugin add cordova-plugin-globalization! Supports numbers, currencies, and dates! Supports getting information about locale/language! Supports getting information about formats! Even supports isdaylightsavingstime because that's still a thing apparently!
More Solutions! Get some random library! Like Moment.js! http://momentjs.com/docs/#/i18n/!
Even More Solutions! Intl! ECMAScript Internationalization API! OMG AWESOME NO PLUGIN NO LIBRARY PERFECT!!!!!!!!!!!!!! 11!!!!! Let's check CanIUse.com!
That other problem...! What does "Add to Cart" look like in French?! Replace buttons/labels/etc with tokens! Replace tokens with the right language value!
Resource Bundle! Set of key/value pairs! Stored by language!
{ "age": "Age", "email": "Email", "firstname": "First Name", "lastname": "Last Name", "register": "Register", "username": "Username" }
{ "age": "年年龄", "email": "电 子信函", "firstname": "名字", "lastname": "姓", "register": "登记", "username": "Username" }
Suggestions! https://github.com/doshprompt/angular-localization! IBM Globalization (https://ibm.biz/bmglobalize)! Demo: http://www.raymondcamden.com/2015/10/14/addinglocalization-to-your-ionic-application-with-ibm-bluemix/!
Example Code!
navigator.globalization.getlocalename(function(l) { console.log(l); locale.setlocale(l.value); }, function(err) { console.log('get local err', err); });
.value('localeconf', { basepath: 'lang', defaultlocale: 'en-us', shareddictionary: 'common', fileextension: '.json', persistselection: false, cookiename: 'COOKIE_LOCALE_LANG', observableattrs: new RegExp('^data-(?!ng- i18n)'), delimiter: '::' }).value('localesupported', [ 'en-us', 'zh-chs', 'fr-fr' ]);
<label class="item item-input item-stacked-label"> <span class="input-label" data-i18n="app.username"></span> <input type="text"> </label>
User Interface and User Experience
General Tips! Test on a real device! Use native UI as much as possible (dialogs plugin)! Use a framework!
Performance! Look at what you load over the network! A secret: JSON isn't always slim (look at the number of rows and the size of each row)! Provide instant feedback!
Performance! Hardware Accelerated CSS (translate3d)! https://www.sitepoint.com/introduction-to-hardware-accelerationcss-animations/!
Performance! Use touch vs click! 300ms! Old news: Removed in Chrome 32 (for mobile optimized sites)! <meta name="viewport" content="width=device-width">! Also removed from IE/Edge, FF, and Mobile Safari in ios9.3!
Performance! Minimize DOM thrashing (dom += <b>poo</b> in a loop)!
Performance! Use the dev tools!! https://developers.google.com/web/tools/chrome-devtools/profile/ evaluate-performance/?hl=en! https://developer.apple.com/library/mac/documentation/ AppleApplications/Conceptual/Safari_Developer_Guide/ Instruments/Instruments.html!
Etc! Accessibility! https://github.com/phonegap/phonegap-mobile-accessibility! Security/Content! https://www.raymondcamden.com/2015/03/13/testing-metacertssecurity-api-service/!
Wrap Up! Contact me at raymondcamden.com! Contact me at @raymondcamden! Share your pain to help others!