CPGG #0 (Common PhoneGap Gotchas Series)

CPGG #0 (Common PhoneGap Gotchas Series)

So, PhoneGap Day EU in Amsterdam has come and gone, and I must say I’m still coming down off the high of being a presenter. The day was absolutely fantastic, even accounting for my severe jet lag and lack of sleep the night before. My sleep schedule is just now getting back to normal!

I thought it would be cool to do a series based on my presentation. There are several reasons:

  • Some of us are readers, and like having things in print. The web may not be literally printed, but the point stands.

  • I can cover some additional facets of particular topics that 40 minutes in a presentation simply doesn’t allow for.

  • You get to see some of the content that just didn’t even make it into the presentation and were left on the cutting-room floor.

I’m not promising that every slide will be represented in this series, nor am I going to follow the original order of the presentation (kind of hard to do when one intends on showing stuff that didn’t even make it!). I do hope to bring you lots of bite-sized posts that hopefully will assist you in developing a great app, and will hopefully help you avoid all the head-meets-desk moments that I (and many others) have personally encountered.

So let’s get started, shall we?

PhoneGap is not a browser

So I know that this perhaps sounds both obvious and quaint, but I’ve run into this misconception quite often, especially from those who are new to hybrid development. Goodness knows, I even initially had the same misconception when I started — all it takes is a good look at some of my old code. (Yikes!)

This misconception is problematic in so many ways, not the least of which is the perception of your app by your end users — and that’s assuming you can even get the app onto your user’s device. See, Apple (and others) will tend to reject your app if it looks like it is simply a wrapper around a website. And for good reason, because each platform has provided mechanisms for what are essentially bookmarks on the home screen.

Furthermore, if one has the mindset that PhoneGap is just another browser, one is apt to code in ways that will simply break in a mobile environment, and one ends up grinding their teeth trying to work around problem after problem after problem.

But I hear you saying — “aren’t PhoneGap and browsers very much alike? Don’t they both use web technologies?” And the answer to those questions is “Yes, but only when viewed from afar”. From a distance, things do in fact look very similar, as the following slide attests:

CPGG: Not a Browser (2/3); Left-side: HTML, CSS, and JavaScript contained within a web view, contained within a browser. Right-side: HTML, CSS, and JavaScript contained within a web view, contained within PhoneGap

The problem is that this view holds true only from a very high level, or when viewing the two from a position with little experience (believe me, I’ve been there!). In reality, the two are very different, as the following diagram should make clear:

CPGG: Not a Browser (3/3); Left-side: HTML, CSS, and JavaScript contained in a web view, interfacing with GPS, Accelerometer, limited storage provided by the device, all contained within the browser chrome, which also provides the browser's user interface, visible security mechanisms, download management, etc. The browser chrome interfaces with more features on the device, including bookmarks, non-sandboxed storage, etc. All of this (and more) is wrapped inside the browser. Right-side: HTML, CSS, and Javascript is contained in a web view, which uses a bridge to connect with native code, including core plugins. This native code interfaces with device features like contacts, storage, in-app purchases, sharing, and SDK features. All of this (and more) is wrapped by PhoneGap

Now, I’m not claiming that this diagram is perfect and that it contains every difference. It is intended instead to show that a browser works very differently than PhoneGap does.

A browser is responsible not just for rendering web content, but for providing a safe and secure mechanism for users to interface with that content. Some of these features are provided as a part of the web view, such as access to certain device features like GPS and a sandboxed storage system. Many visual features we often associate with browsers, such as the “this page is secure lock” that users are (hopefully) accustomed to seeing aren’t part of the web view at all — they are rendered by the browser’s chrome. The same applies to HTTP basic authentication challenges — the browser is responsible for rendering the user interface in which the user can type a username and password. Download management is another good example: the web view may initiate the download, but it’s the browser’s chrome that provides the user with the mechanism of viewing progress and stopping and restarting the download.

PhoneGap, on the other hand, doesn’t provide your app with any of these extra features that a browser provides. It exists to provide a bridge between web technologies (JavaScript, HTML, and CSS) and the native features provided by the device. The way it accomplishes this is to provide a native code layer that knows how to interface with the web view (as well as the reverse: there exists some JavaScript that understands how to talk to the native code layer). By default, this doesn’t do a whole lot until you add in some plugins. When you add a plugin to your project, you gain access to certain native functionality. For example, if you add the “device” plugin, you can get lots of useful information about the device your app is running on, including manufacturer, operating system version, and more. If you add the “contacts” plugin, you can interrogate the contacts stored on the user’s device (with permission, of course).

Notably missing in what PhoneGap provides is anything regarding the browser chrome mentioned above. If your code needs to perform an authentication challenge, it is up to your code to provide the user interface and logic to carry the challenge out. If your app needs to provide download management, then it is up to your app to provide all the logic and user interface to do just that. In short, PhoneGap expects you to provide the entire user interface for your mobile app, whereas the browser often provides at least a portion of the visible user interface for your web app.

Don’t wrap a website: keep your code local

Wrapping a website is a question that often pops up in the support forums. Yes, it’s technically possible to build a PhoneGap app that simply loads a remote site. It’s really easy to do, in fact. But you shouldn’t. Why?

  • Your app will be rejected if you submit to Apple (and perhaps other stores).
    • Note: this point doesn’t really apply to enterprises using an MDM tool to distribute their app.
  • You’re wasting the user’s precious space. It takes far less storage space to store a bookmark on the user’s home screen than it does to include all of PhoneGap’s native code just to provide the same experience. PhoneGap isn’t big, but let’s face it: there are devices out there that are running close to zero bytes free, too.
  • Your app is fragile with regard to network conditions.
  • Your app is susceptible to security issues that put your user’s data at risk.

The latter two are pretty important, in my opinion, and are great reasons as to why as much of your app’s code as possible should be local to the device.

The network is far from perfect

Just because your network connection to the outside world is great, doesn’t mean that everyone else’s is. For example, my current network connection is a rather paltry 10mbps down and 1mbps up. While better than many others on the planet, it’s really pretty sad when used in conjunction with data hungry apps. Good luck trying to play two or three simultaneous video streams on my wi-fi — it’s just not going to happen. The same applies to cellular connections — you can’t assume that a LTE connection will have lots of bandwidth and that it will be fast — the reverse is often the case.

Of course, bandwidth isn’t the only potential issue when it comes to network connectivity. Latency and reachability can be huge problems. For a while, I was seeing ping times north of 30 seconds with my ISP, and that’s when the request didn’t fail completely. Did I have access to the Internet? Yes. Did I have reliable access? No.

If you simply create a PhoneGap app that then redirects to an external site, you’re risking falling afoul of all sorts of conditions that your app can’t handle precisely because there is no local code to handle the failure conditions. For example:

Scenario Result
No network connection / no route to server App fails to launch at all
Limited bandwidth / poor latency App starts slowly (and may visibly stream in)
Interrupted / corrupted download App may fail in unexpected and novel ways

On the other hand, with local code, you can properly respond to these scenarios, like so:

Scenario Result
No network connection / no route to server Display a friendly error message or show cached data; offer data sync
Limited bandwidth / poor latency App still starts quickly, and can render a “this is taking longer than usual” message, if needed
Interrupted / corrupted communication App can detect and react accordingly

Now, one issue often mentioned with regard to local code is that of performing live updates. It’s easy to update a web site: you push new changes, and everyone gets them on their next visit. But a consumer app is typically distributed through an app store, and one often has to undergo review prior to release, and not everyone will update.

Here’s the thing: hot code push is a thing, and even Apple allows it now. Check out Microsoft’s Code Push for a great example of this. Although I prefer to update through the app store (for a variety of reasons), if this feature is a must, it’s possible even when keeping most code local.

The network is not secure

Here’s a bigger reason why you shouldn’t just wrap a website: you have no way of guaranteeing that the code your user receives is the code you sent. Man-in-the-middle (MITM) attacks are a thing, even if you use HTTPS. When distributing your code via an app store update, you lower the risk — code updates are signed, and devices will usually refuse to install apps that aren’t properly signed. The security surrounding app updates is handled by the app store, and your life is that much simpler (if a bit slower while waiting for reviews to finish).

If you just redirect to an external site, there is no mechanism for detecting if the SSL certificate is the one you expect, which means that a malicious attacker could inject their own code into your app and can intercept your user’s data, even if you use HTTPS. By doing so, your user could be at extreme risk for identity theft and invasion of privacy.

Hot code push, if required, is a happy medium between the realm of purely local code and purely external code. The push mechanism has local code on hand to deal with network connectivity issues and can also verify authenticity of the received bits. Just a word of advice: don’t try to roll your own hot code push solution unless you want to lose a lot of brain cells and gain a lot of paranoia! There are a lot of edge cases that code push solutions have to deal with, and missing any of them can put your user’s data at risk.

Next time on CPGG

We’re going to continue in this vein for a couple more posts probably. Another common issue when treating PhoneGap like a browser is the app’s own architecture. I’ve seen a lot of people (myself included) try to build apps like a website, when instead one should embrace “single page architecture”. What does all that entail? We’ll find out next time!

Leave a Reply