Skip to content

Do you need a mobile app? Probably not

This post from the folks at 18F does a great job of covering why you should default to a responsive web site rather than a native mobile app. While tools like cordova and react native decrease the effort required to build a native application, the ongoing maintenance costs shouldn’t be underestimated.  It is easier to outline the reasons why you should build a mobile application, because there are far more reasons why you should not. From the post I mentioned above:

  • extreme bandwidth constraints or offline operation
  • heavy use of sensors that are not web standards
  • third party interactions

I’d add:

  • branding needs, where you have a compelling application and expect to be be installed on the user’s home screen. Expect to spend $$$ on marketing the app
  • extreme performance. This might be graphics/video, battery or network performance

and, via twitterSara Bates added:

  • push notifications, (if used wisely)

If your application doesn’t meet these criteria, I’d think long and hard about launching with a native mobile application, and think about what you could do for your business with the extra budget.

You can likely prototype your app with a responsive website and then build a native mobile app when you know more and/or have user feedback. This can be a great way to economize, because you can leverage outsourced mobile app teams and point them at the prototype as a living requirements document.

Headline: Android User Buys App

cash register photo
Photo by liewcf

A few weeks ago, I bought my first app on Google Play.  Wait?  I thought Android users don’t buy apps?  Well, what can I say, I like to break the mold.

Actually, I think I’m pretty typical for a high end Android phone owner.  I have had an Android phone since 2010–I paid hundreds of dollars for each of my phones.  My wife is a diehard iPhone owner.  At the time I purchased, she wondered why I wanted to buy an Android.  The application process for writing apps is one reason, and another is being able to write an app, on whatever computer I wanted, and install it on my phone.  Now I’m in Google’s ecosystem, and it would take a lot to pull me out of it.

Regardless, I finally bought an app!  I was looking for music on my phone, and have long been a fan of soma fm, ever since John Argo introduced me to them–about a decade ago.  Groove Salad is excellent for doing development.  I looked up their app, and it was $4.  soma fm is one of those organizations that I’ve been meaning to contribute to for years (like KGNU, they are listener supported and commercial free), but never got over the hump.

This was my chance to support the radio station which I loved!  Google made it easy–just had to enter a billing method (options included credit card, paypal, and bill to my phone account) and re-enter my password.  (Yes, I realize this was a small donation in the scheme of things.  The app has convenient links to the donation page.

So, what does this anecdote mean for people looking to make a living selling apps?

Don’t count on me, because the only app I’ve ever paid for was because it was a donation.

I had a long conversation with a friend about this and it appears to me that mobile apps are, in the vast majority of cases, complements to existing businesses, and not businesses themselves.  That was my experience at 8z as well. Being a complement is still a ginormous market, but it isn’t a goldrush for individuals.

Running multiple versions of Cordova 3.x

cordova, the command line interface to the Cordova development framework, is a node package. npm, the node package manager, has the concept of a ‘global’ install and ‘local’ installs. Typical installs of the cordova command line interface instruct you to perform a global installation. That is what the -g in npm install -g cordova (from the docs) means. Installing globally means that one version of cordova is available to every user on that computer, and will be installed in a system directory (for example, /usr/local/lib/node_modules, on linux). If you upgrade that one version, everyone and every project on the system will be upgraded (or forced to upgrade, depending on your perspective).

If you want to run different versions of cordova for different projects, you have to install locally. That means that all the cordova code will be installed in a local directory, rather than a system wide directory.

Why might you want do this? Any number of reasons, but primarily because the relationship between your application and a particular version of Cordova is important.

  • If your application depends on bugs or feature behavior that has changed between versions, you could need to freeze your application at a given version of Cordova, at least until you were able to update your application and test it against a newer version.
  • You could have multiple applications that were developed at different times, and the older ones could crash if upgraded (or perhaps you don’t have the time to test against the latest cordova version).
  • Applications under active development may be at the latest and greatest version of cordova, while the others may be sitting at what was the latest and greatest when they were last modified.
  • A local install will let you test your application against a new version of cordova without committing a global install, which might affect other team members, other projects, or necessitate a downgrade if the new version has issues.
  • You might be working on a platform that is not amenable to being place in a virtual machine (like iOS) and yet still want to run different versions of Cordova on the same machine.

Below, I outline steps to follow if you want to have one project using Cordova 3.3 and another using Cordova 3.1. npm view cordova lets you view the available versions–typically you want the latest minor revision (3.3.1-0.1.2 is better than 3.3.0-0.1.0). These are steps for Android, but it would be similar for any target platforms. And these steps assume you have successfully installed the target platform tools for Android previously.

mkdir cordova3.3 # or cordova3.1
cd cordova3.3 # or cordova3.1
npm install cordova@3.3.1-0.1.2 # or 3.1.0-0.2.0
mkdir project
cd project 
../node_modules/cordova/bin/cordova create test33 io.cordova.HelloWorld33 # or test31 io.cordova.HelloWorld31
cd test33 #(or test31)
../../node_modules/cordova/bin/cordova platform add android
../../node_modules/cordova/bin/cordova plugin add org.apache.cordova.device

Don’t forget to add the device feature to your config.xml

<feature name="Device">
    <param name="android-package" value="org.apache.cordova.device.Device" />

You need to update the www/js/index.js file to display your Cordova version. This is only to prove you have different versions of Cordova running on the same machine

onDeviceReady: function() {

Finally build the application and run it on your emulator:

emulator -avd avdname # start a previously created avd via the android command
../../node_modules/cordova/bin/cordova build android
../../node_modules/cordova/bin/cordova emulate android

Note that there should be no issues with running applications built with different versions of cordova on the same device–the applications are all sandboxed.

If you are often in this situation, you can create aliases that point to the correct version of the cordova command, since the results are indeterminate if you mix and match calls to different versions. For example:

alias cordova31='/path/to/cordova3.1/node_modules/cordova/bin/cordova'
alias cordova33='/path/to/cordova3.3/node_modules/cordova/bin/cordova'

Incidentally, I tried these steps out with the latest version of the android tools (version 19 of the Android build tools) with all four of the latest minor revisions of cordova: 3.0.10, 3.1.0-0.2.0, 3.2.0-0.4.0, and 3.3.1-0.1.2, and could only get the 3.1.x and 3.3.x versions to work. So another reason to do a local install is to perform a quick check to see if your platform installation is compatible with a given version of Cordova.

Do you have different versions of Cordova installed on the same machine?

How to collect usage statistics in your phonegap/cordova application

My company recently wrote a couple of mobile applications. Since one is for consumer use (search for ‘8z neighborhood’ in the App Store/Google Play if you live in Colorado or the Bay area and want to check it out), I wanted to know what type of users were downloading and installing it, what was being used, and other general usage statistics.

I asked a mobile app vendor we’ve worked with what they used for usage stats, and they said Flurry. I also looked at Google Analytics, Mobile–this is a nice q&a explaining the major players in the mobile analytics market. We didn’t want anything complicated, just basic stats with the possibility of collecting further information in the future, so I went with the vendor recommendation. Flurry also works with the two platforms we were targeting: IOS and Android, as well as many others.

Flurry is zero cost, but nothing’s free–they want your data and you grant them a “right, for any purpose, to collect, retain, use, and publish in an aggregate manner” all data collected from your application. I’ve seen similar TOS from most of the free analytics vendors, so this was no surprise.

To use Flurry with cordova/phonegap, and with plugman, I was ready to plugmanify an existing Flurry phonegap plugin. Luckily, someone else had already done it. All I had to do was update the plugin to work with Cordova 2.9, and to use the latest IOS7 compatible Flurry library.

After you install the plugin (I recommend doing so in an after_platform_add hook script), you simply add this to your code after the deviceready event fires: window.plugins.flurry.startSession(sessionkey). I inject the session key using a hook script, because I wanted a different key for stage and production builds, and also for each device platform (Flurry requires the latter). Because hooks only get the root directory as context (although this is supposed to change) I had to put some logic in the javascript to call startSession with the appropriate key:

 App.config.flurryid = "";
    if (window.device && window.device.platform) {
        if (window.device.platform == "Android") {
            App.config.flurryid = /*REP*/ 'notreallyanandroidflurryid' /*REP*/ ;
        if (window.device.platform == "iOS") {
            App.config.flurryid = /*REP*/ 'notreallyaniosflurryidxxx' /*REP*/ ;

Although I have not used any of the more specific event tracking, the basic statistics are a great start (including new users, retained users, device versions, etc).

Don’t fly blind when you release your phonegap/cordova mobile app–use Flurry or something simliar.

Towards a native maps plugin for PhoneGap/Cordova and Android

I recently did some prototyping for a native maps plugin for Android.  For iOS/phonegap, you have the mapkit plugin which I was able to get working on phonegap 2.0, with some help from the google group.  But for Android, the concensus seems to be that you should use the web version of Google Maps (either the javascript version or the static map images).  While that advice works for a subset of users, if you pull out your Android phone and compare the performance between the web version of Google Maps and the native app, you’ll quickly choose the native app.

There are two paths forward for a native map plugin.  The main limiting factor is that a native map view is only instantiable by a MapActivity,”because it depends on threads which access the network and filesystem in the background; these threads must be shepherded by the lifecycle management” of the MapActivity.

So, you can either:

  • have your app be managed by a MapActivity and embed a Cordova webview in the app.  This would probably work well for apps that are really really map heavy, and only have a slight bit of webUI.  I’m not sure what value PhoneGap brings to that type of app, though.  It also seems pretty complex.
  • or have the PhoneGap app transition from DroidGap activity to the MapActivity and then back.
I went with the second choice.  As I said, this was an exploration, so there are plenty of problems that I skipped that will need to be solved to have a robust plugin:
  • which activity/technology gets the points to display initially
  • which activity/technology gets points as the map is moved around
  • testing on a real device (what do you do when you are running an Android device without native Google maps)
  • passing full featured events back and forth between PhoneGap and the MapActivity


Geolocation and the Android 2.3.3 emulator

Just so someone else doesn’t waste an afternoon banging their head against a wall, here’s how to make the Android 2.3.3 emulator work if you want to access geolocation.  This applies to the javascript apps I’m writing–I don’t know if a native app would have the same issue.

  1. Install an Android 2.2 AVD (2.3.3 doesn’t work with geolocation).  Make sure you enable the GPS in your hardware settings when setting up the AVD.  That’s right, the first step to making the Android 2.3.3 emulator work is to downgrade to Android 2.2.  Why would you want to target 2.3.3+?
  2. Make sure you add <uses-permission android:name=”android.permission.ACCESS_FINE_LOCATION” /> to your Android manifest.
  3. Add <uses-feature android:name=”android.hardware.location.gps” android:required=”false” /> just to be sure.
  4. Start your emulator and install your software.
  5. telnet localhost 5554 (if you don’t have telnet installed on Windows 7, here’s how to enable it).
  6. In the telnet window, type in “fix geo -101 50”.  Note that you can’t use the backspace, so cutting and pasting is your best option.  Also note that longitude is before latitude.
  7. Execute the action that requires a geolocation.  (If using phonegap, make sure to pass these options to the geolocation call: { enableHighAccuracy: true }.)

You should see a GPS satellite in the notification bar of your emulator.

Also, note that each time you execute the action that calls the geolocation service of your phone, you have to type the ‘fix geo…’ line in the telnet session.

I also found this page useful for testing.