Blog

Blog Archives - 5 Record(s)

Year: '2015' - Month: '5'

30
May 2015

Gavin Pickin

Cordova Hooks - Deeper Dive into my Environment Setup Hook Written in NodeJS

Android, Cordova / Phonegap, Dev.Objective, Ionic, IOS, Mobile Development, Node.js

After my session about Dev.Objective() called “Getting your Hooks into Cordova - Workflows and Build Helpers”, I decided I should do a deep dive into each of my Hooks I discussed in my presentation, and today we’ll look at my Environment Setup Hook, written in NodeJS.

My presentation mini site is available here on my blog at http://www.gpickin.com/devobj2015/cordovahooks/

As I add more blog posts about this topic, I will continue to update the mini site.
The minisite has links to the gists of all the hooks I had, the slides and links to the few blog posts I did find on the topic.

For more information on what hooks are, please refer to my Session Review and Overview here: Post Conference - Session Review - Getting your hooks into Cordova- Workflows and Build Helpers

One of the first Hooks in my hybrid mobile workflow with Cordova, is my environment setup hook.
This hook is setup to run in the BEFORE_BUILD.
This hook is written with NodeJS, so it will work on MacOSX and Windows, and this hook is useful with iOS, Android, Windows, any Hybrid Mobile Platform. 

When working on an app, on your development machine, or in staging for a customer, or when pushing to the App store, you are most likely going to have certain aspects of your code that behaves differently. You can manually change these variables, or comment out your console.log when pushing to the app store, but thats a big pain, a pain point… so this is the solution I came up with.

First step, I decided to remove the tight coupling with the environment, by removing the API urls, API keys, debug flags etc from inside the code itself, and created a file called env.js which contained a variable with those environmental settings in it, that I include in my project. This allowed me to manually uncomment the right Javascript Object, and when I build, then my app would refer to app.env.api_key to access the correct api key.

Next step was to automate this process, this is where the hook came in.
I setup a file for each environment I wanted to use. env.debug.js and env.staging.js and env.prod.js in this case. 

The hook copies the contents of the right file, into env.js, and then my app loads that object and the code references that for anything environment related.

Lets look at the code, and I’ll break it down as we go.
https://gist.github.com/gpickin/9b6edbfa49d2879b4359

 

#!/usr/bin/env node

First line… you need a line to define what type of hook it is, so the right application can process it. In this case, its Node

 

var environmentList = ['debug','staging','prod'];

This next line sets up the list of environments I want my app to support. This also enforces the environments, if one is passed that is not in this list, the app will default to the first item in the array, you’ll see that soon.

 

var fs = require("fs");
var path = require("path");

Next we include 2 node modules we’ll make use of in this hook.

 

console.log('-----------------------------');
console.log("Running hook: "+path.basename(process.env.CORDOVA_HOOK));

Next we output some text to the console, to provide an update to the process, a separator, and a line telling the user what Hook is starting to run.
var buildEnvironment = environmentList[0];
This is where we set the build Environment to the default, which is the first in the array. If all else fails, the hook sets up the app for this environment.

 

if (process.env.target && environmentList.indexOf( process.env.target ) > 0 ) {
    buildEnvironment = process.env.target;
    console.log( 'Setting environment');
}
else {
    console.log( 'Using Default Environment' );
}

Next, if there is a target environment passed in, and it actually exists in our array of environments we intend to support, then we set the buildEnvironment to that target.
Otherwise, we leave the environment set to the default, and proceed. 
In both cases, we output a message to the CLI so the user can debug if needed.

 

console.log('Using environment: ' + buildEnvironment);

We output the name of the environment we will be using, again for debugging.

 

var theSourceFile = path.join( path.resolve(),'www','js') + '/env.' + buildEnvironment + '.js';
var theDestinationFile = path.join( path.resolve(),'www','js') + '/env.js';
console.log( theSourceFile );

Next we set the source and destination file paths, so we can work with them.
We output the name of the source file to the CLI.

 

if (fs.existsSync(theSourceFile)) {
    console.log('it exists');
    ...
}
else {
    console.log('Config File ' + theSourceFile + ' NOT FOUND');
    console.log(theDestinationFile + ' NOT CHANGED');
    console.log('-----------------------------');
}

The next section has a large if statement, if the source file exists, we log that it exists, and then proceed (code below), otherwise we log the fact the source file was not found, and the env file was not updated… and the hook ends.

 

fs.readFile( theSourceFile, function(err, buf) {
    ...
});

Inside the if, if the source file exists, we read the file, and the result of this async function, is err, data, where data is the contents of the file. Since there was no encoding passed, data is in the form of a buffer. 

 

if (typeof buf !== 'undefined') {
    ...
}
else {
    console.log('Config File ' + theSourceFile + ' NOT FOUND');
    console.log(theDestinationFile + ' NOT CHANGED');
    console.log('-----------------------------');
}

Next we check the buffer, if the buffer is not undefined, we process more. Otherwise we output the source file was not found, and the destination file was not changed, and we stop processing the hook.

 

console.log('Read from file ' + theSourceFile);
fs.writeFile(theDestinationFile, buf.toString() , function(err) {
console.log('Wrote to file ' + theDestinationFile);
console.log('-----------------------------');
if (err) throw err;

Next we output that we read the file, and then we convert the buffer.toString() and save to the env.js file. We output that we have completed, and the hook has ended.

Now, how do we actually use this hook? On *nix systems, like Mac OSX, we can just prepend environment settings like below
#: target=prod cordova build ios

On windows, you have to change things up… you use the set command, to set environment variables first, then use the cordova build command
#: set target=prod
#: cordova build windows

Here is the whole file… also available at https://gist.github.com/gpickin/9b6edbfa49d2879b4359

 

 

The beauty of this is, it is simple, and easily extended, so you could add targets for iOS, Android etc too, and then build even more complex setups.
Its saved me hours of time already, let me know if you use something like this, and what else it could be used for.

Thanks for reading.

27
May 2015

Gavin Pickin

Post Conference - Session Review - Getting your hooks into Cordova- Workflows and Build Helpers

Android, cfObjective, Cordova / Phonegap, Dev.Objective, Ionic, Javascript, Mobile Development, Node.js, Unit Testing

May 15th, 2015 was the last day of dev.Objective(), and the last session of the day had some great topics, “Devops: journeyman to infrastructure mastery”, ‘Marketing for Developers’, ‘Level Up your Javascript: Understanding the confusing bits’, ‘Web sockets, yes they can do that too', and my session, ‘Getting your Hooks into Cordova - Workflows and Build Helpers'. With mobile and hybrid development really growing into a track of its own, I decided to submit this topic, as I believe Cordova Hooks are a big part of Cordova mobile development, they save me hours every week, and they are relatively unknown if you search for blog posts about them. When the session was accepted, I took that as a challenge to up my game and really research hooks, and make my presentation a complete resource.

I did not expect a big crowd of people, especially with the competition of the other topics, and of course a lot of people leaving early for flights, or saying their last minute goodbyes. We had a small intimate group, which allowed us to have a very open conservation, and I think we all got a lot out of the session.

For those of you who do not know what Cordova hooks are, they are scripts you can run automatically at given points during the development process, at these points, events are triggered and any hook listening for that event will fire For example, every time you build the app for iOS you can fire a hook that inserts a special iOS themed CSS, or anytime you build your app, after build you could run uglificatiom and minimization of your files.

Hooks can be written in bash files, bat files, but it is recommended to use NodeJS since the CLI is written in node, so its obviously platform independent and available.
Having attended the Birds of Feather (BOF) the night before my presentation, I was inspired to write a few new hooks the day of, and that went over really well with everyone.

These are the hooks I showed... and what they do, I intend to post a separate post for each individual hook, and will update this post and the mini site accordingly.

Environment Setup-  before_build
This hook allows you to set an environment variable at the command line, and change the output of the build, depending on if you’re building for dev, staging, or production. This makes it easy to update API urls, api keys, debugging output, and much more.

CordovaCleanup - before_build
This is a simple script that cleans up those annoying operating system files like .DS_Store and Thumbs.db etc. It could be configured to clean up more. This can be configured and extended to suite your development needs.

JS Hint - before_build
This hook has a list of directories I want the build process to lint with JS Hint. This step hints all my code and exits if it finds errors, giving me all the info I need to fix it, before building again.

Jasmine Unit Tests- before_build
After my JS Hint hook has fired, and succeeded, then my Unit Tests run with Jasmine. If the unit tests all pass, the build continues, otherwise the process ends. Success or failure, Jasmine outputs number of specs, execution time etc.

JSON - before_build
This hook runs before build, and hits web service for a Json response, and stores the file in your app, so when packaged, your app has a semi recent set of data to come preloaded, without the need of a full sync.

Uglify - after_build
This hook runs after the build and uglifies and minifies the files in the location specified.

My presentation mini site is available here on my blog at http://www.gpickin.com/devobj2015/cordovahooks/

As I add more blog posts about this topic, I will continue to update the mini site.
The minisite has links to the gists of all the hooks I had, the slided and links to the few blog posts I did find on the topic.

I really think hat Cordova hooks are awesome, if you are a Cordova developer, or Ionic developer (Ionic cli is built on top of Cordova), give them a try.
If you are using them, please share some of the hooks you are using.

Thanks for reading.
 

26
May 2015

Gavin Pickin

A quirk of Cross Platform WebSQL in Hybrid Mobile Development for iOS Android and Windows

Android, Cordova / Phonegap, Ionic, Javascript, Mobile Development, Techie Gotchas, WebSQL

When is WebSQL not compatible across devices? This is really a quick question, as if you recall reading in previous blog posts ( if you haven’t read them, I urge you to ) I am using WebSQL for my hydrib mobile app development with Phonegap and Cordova… and although WebSQL is supported on Android and iOS, it is not natively supported on Windows Phones / Devices. That is where the lovely people at MS OpenTech come in, Microsofts Open Source company, which wrote a WebSQL wrapper for SQLite to allow you to work with SQLite like you would WebSQL. FANTASTIC, until you hit those issues… so lets look at a couple of them.

I have not tested every SQL syntax, I am sure there are plenty of other issues, and gotchas, like the “Loading or Duping Large Amounts of Data into WebSQL - Options with Performance Numbers” where there are differences with multiple queries, vs single query multi value. 

Today, I am reminded that sometimes the simplest of SQL is not available. While I am working on my app, I quite often change the DB structure, adding new tables to my app. In that case, I usually use:
CREATE TABLE IF NOT EXISTS test

This obviously, creates a table called test, if it does not exist. Quite handy, when you’re adding  tables to your app, if it doesn’t exist, it adds it. If you try and add a table, that does exist, if gives you an error, so this is a painless way to do that. 

If you want to change the data structure of a table, and you do not want to deal with migration scripts… in development, you simple drop the table, and then create it, so you might just use:
DROP TABLE test

That will of course  error, if the table doesn’t exist… so I usually use:
DROP TABLE IF EXISTS test.

You might say: 'Thanks Gavin for the advice, but whats you’re point?'

Even thought SQLite documentation seems to support the IF EXISTS and IF NOT EXISTS, this wrapper written around the SQLite library, by MSOpenTech in the Cordova plugin, does not actually support this. 

So instead of using:
DROP TABLE IF EXISTS test 

I simple use:
DROP TABLE test

And then I have to catch the error it throws when it tries to drop a table that does not exist.
Of course, if I drop the table, all the time, then I can just CREATE the table.

Its not a complicated incompatibility, but when you develop and test on iOS... and then convert to Windows, which uses a wrapper, you need to remember.

KISS - Keep it simple stupid.

I wonder if the code using joins in updates work as expected... I guess we'll find out soon.

 

Thanks for reading.
 

22
May 2015

Gavin Pickin

Strange offline issues with Mac Mail and Gmail over Imap

Techie Gotchas

This is a super short and sweet post, mainly a reminder for myself. Using a mac, I have moved over to using Mac Mail, and for the most part it behaves pretty well.Sometimes I have noticed that I lose my IMAP mail connection with Google. You know that GOOGLE and Gmail should not be down, so what is the problem?

It turns out, when you add a Gmail account in mac mail, the server it defaults to is imap,gmail.com. I do not know if it is a load issue, or something else but the fix just required me switching it to another server name.

Use Server: imap.googlemail.com
Instead of : imap.gmail.com

Since then, I have not any issues... strange, but easy fix.
Hope this helps someone, even if its me in a few months

21
May 2015

Gavin Pickin

dev.Objective() is over, returning back to normal life.

CFML Language, cfObjective, Conferences, Dev.Objective, Javascript, Mobile Development, Unit Testing

dev.Objective() conference held last week in Bloomington MN, with IntoTheBox the day prior, was a great geek week as I like to put it. Of course a conference is most importantly there to give you information to grow and learn, but networking is a close second, and it was great to catch up with friends, and make some new ones at the same time.I was lucky enough to be picked to present not one, but two sessions this time, which adds a weight to your shoulders, but is great to give back, and be on the other side of things.

As usual I spent many hours looking over the schedule, trying to decide what was the best session for each spot, or in most cases, what was something I could miss and get another chance to see it online, or at another conference. Every session left me almost regretting my decisions, but every session held strong and left me feeling good, having learned and grown from what I absorbed. I tried to take notes, and did so for the first day, but presenting on the second and third days meant I had my focus elsewhere. I will write a recap of the sessions I went to, with my opinions here soon, I am trying to make sense of my notes still, and reflate them into meaningful summaries.

My sessions went really well, with a full house in my first talk, "How do I write Testable Javascript?", and only a handful to my "Getting your hooks into Cordova" which was up against some great sessions, and was the last talk of the conference. I actually quite liked the small group, we openly talked and discussed things as we went. I intent to write up each session with a summary soon, and link to my slides and resources, as well as write some follow up posts regarding questions from the talks, or just more in depth looks at the "COOL" parts

You cannot have a conference with people, and I loved chatting with old friends, and new friends, and I think every year it just gets better and better. In fact, I had so much fun, I actually invited everyone via twitter to connect with me via Linked In at http://linkedin.gavinpickin.com and I created a slack channel for all of the dev.Objective() attendees to talk in and keep in touch. If you would like an invite to the slack channel, send me a DM on twitter and I will invite you asap.
It was a great year, I missed my family, but if I was going to be away for them, this is a good reason to do so. I didn't like the plane ride home, or missing one, but even in the airport, I made some great contacts, had good conversations, and came back pumped and ready to put everything into practice.

If you did not go this year, make an effort for next year.

NC DevCon is still coming up, and CF Summit too, plus, you can step out of the CFML World and try other conferences too. Some of my new best friends came from outside our cfml circle... crossing boundaries and putting yourself outside of your comfort zone can force you to grow and learn quickly.]

Check back soon for more information on how my talks went, which talks I went to see, and what I took home and plan to play with.

 

NCDevCon - http://ncdevcon.com/
NCDevCon Tickets - http://ncdevcon.eventbrite.com/
Submit a talk to NCDevCon - http://www.ncdevcon.com/extensions/callforspeakers/SessionForm.cfm

CF Summit - https://cfsummit.adobeevents.com/
CF Summit Tickets - https://cfsummit.adobeevents.com/register
Submit a talk to CF Summit - http://cfsummit.cfml.us/

dev.Objective() - http://www.devobjective.com/

Blog Search