3/01/2013

PhoneGap: An Unexpected Journey

This is a story of a web developer, who's a complete newbie in mobile world and who were given a task to research and develop a tablet application from scratch, re-using his experience in web technologies, i.e. using PhoneGap.



So, my friend, if you are like me - go on reading. This article will give you an intensive look at what PhoneGap is from a perspective of web developer.

Part 1. Theory

Chapter 0. What is PhoneGap?

I suppose you all have an idea of what it is, but I'd like to stick to a definition and point out couple of things. So, as they say,
PhoneGap is an open source framework for quickly building cross-platform mobile apps using Html, Css and JavaScript
And it is true(to certain extent). Lets take a deeper look:

Open Source - yes. you can delve into implementation details and even fix their bugs if you want to. But I wouldn't recommend doing so.

Framework - as you will see later, PhoneGap is just a little piece of javascript and platform specific language. There's not much mystery in it.

Quickly - this really depends. Read further to see the answer.

Cross-platform mobile apps - this is the thing that brings attention of clients and managers. It seems that you can simply write your code once and run on any device, saving tones of time and money. Unfortunately the truth is not so astonishing.

Html, Css and JavaScript - yes, yes and yes! we're here because of these cute little guys:) I personally love'em and was very glad to know that I can use them in mobile world.

Chapter 1. Origin

Anyway, how and why did people end up with a product such as PhoneGap? This is a nice one. Here the creators talk about their beliefs and, I must say, they are pretty original. Like these two:
The web solved cross platform.
The ultimate purpose of PhoneGap is to cease to exist.
By and large PhoneGap creators are web consultants and they purely believe that web technologies are perfect fit for writing cross platform solutions. Actually, I totally agree with this one. Just think - on how many devices you can run a browser, in which you can run your app? I have one even on TV!

Also they believe that creating PhoneGap will help standardize web technologies. And according to their beliefs, when there's no more need for PhoneGap(i.e. you can write native mobile apps with web techs without any frameworks) - their task is done. A brave goal, goal worth fighting for, imho, but a struggle won't be easy. Well, good luck for them!

Chapter 2. Implementation

As you may know, PhoneGap isn't the only tool that allows similar functionality. And there's a lot of noise about how these tools work(like this one) and I must say it looked like magic to me for a while. Honestly, I was a bit disappointed...but more on this later. Lets talk about more obvious things first.

So, we have our small html website. And we want it to become a mobile app. Also, we want it to use specific device feature, let it be camera. Where do we start from?

First, we need something to run our site, parse html, translate/compile js etc. In web we have browser. What do we have in mobile app? As you may know, a mobile app is just a piece of executable binary code, which special device knows how to behave with. But our web site is a piece of text! My iPhone doesn't know how to run it as app! The answer is WebView(the name depends from platform). So what is it? 

A WebView is kind of a built-in browser, that can be embedded into a mobile application and which knows how to run html-based web sites. Every platform has its own implementation of WebView, for example on Android you have android.webkit.WebView class, on iOS you have UIWebView, on Windows 8 you have 
Windows.UI.Xaml.Controls.WebView class etc. General pattern is that this built-in browser behaves almost the same as native browser for this environment, e.g. Safari on iOS. Unfortunately, almost...but more on that later.

So, first problem solved - we have our runtime environment. But how do we access a camera? None of popular web browsers has provided us with stable version of camera API, so it is doubtful that some built-in ones will. This is were tool like PhoneGap comes in handy. It gives you a javascript file which has declaration of pure js methods, which know how to access device's features. All you have to do to use it - is include it as a script in your html file, and voila!

Chapter 2.5. Implementation. Learning the Magic.

But for me this was still not enough. This place seemed like the most magic for me. How can javascript access native features, if on exact platform you have special language-specific API for that? Is there some kind of js-to native code translator? But how does the runtime translate js calls into Java code? into Objective C? And back?

Now, sit down kids, and listen carefully, as we're going to learn some magic!

First let me say - kudos to people who implemented PhoneGap, for their creativity and braveness.
As it turned out, js to native communication bridge implementation differs depending on platform, as you can see here(android) and here(ios). Furthermore, each platform has about 3-4 implementations, each fixing some bugs from another one. I can only imagine perplexity and frustration on brainstorming meetings while looking for new ways to handle new bugs in new hacks. Phew!

I won't cover all the ways of communication, but will give some tips.

Prompt

On Android, in WebChromeClient class, there is a way to intercept javascript's prompt message using method onJsPrompt from Java. This gives us a flat-footed way to send messages from js to Java and back(here it is).

You can also find an extended non-PhoneGap related sample here.

"WAT? This ain't magic, Gandalf!" - you say, and I would agree with you. Let's move on. But just let me enjoy this piece of comment with you

Since we are hacking prompts for our own purposes, we should not be using them for this purpose, perhaps we should hack console.log to do this instead!

Perhaps, you should!

JsObject

The WebView class exposes method addJavascriptInterface which lets you bind js calls directly to Java calls, with just a couple of conventions. This looks more right, as for me. Why didn't they use it all the time? well, here's a complete answer I guess. To wrap up - couple of compatibility bugs, as I mentioned before.

So, one could say - we solved the problem. We have runtime, we have communication with native API...did we miss something? Yes, performance. Most operations require some time to execute, and we don't want our GUI to freeze. That's why PhoneGap supports asynchronous model of communication. And as you can guess this creates some obstacles. How should we send messages back from Java to Js? 

Most of the work is done in NativeToJsMessageQueue.java class. The name actually speaks of itself. It's a thread safe queue of js messages to be invoked on js side. This guy's job is to deliver them. Internally he has 4 ways to do this, but I will tell you only about the default and the most hacky one.

OnlineEvent

As some of you may know, there's a thing called Online/Offline event in html5. Basically it's a way to tell your js code that user's device have connected/disconnected from Internet. I'm not sure if all browsers have agreed on the API yet, but there have been some efforts. Anyway, our lovely PhoneGap found a good use for this event! You getting there? Yes!


Bingo! Hack in a pure form:)

So, to sum up, PhoneGap has lots of ways of communication between native and js sides, each for a specific platform/version/situation. It is so, because mobile vendors didn't have an intention to let this happen on every platform same way. And this is what PhoneGap was meant to do. So this is the core part, and I must say, they wrapped the dirty job pretty good, so that the upper level doesn't have to worry about these details.

Chapter 3. Architecture

Generally speaking, PhoneGap has a plugin-based architecture. Each device-specific feature is a plugin, which consists of javascript and native sides. Js side should be as cross-platform as possible, whereas native side can be implemented only once, for 1 device. Nevertheless built-in plugins are developed for all of the most popular platforms, so no need to reinvent the wheel. I'm not going to tell how they should be built - there are tones of guides for this. 

What I would like to say is that this architecture, together with open source code, not only allows you to fix their bugs, but also allows you to tweak their plugins for you needs. And you can also built your own plugin, and support only on the platform you want. Maybe somebody will extend it to his needs. Maybe you will extend somebody's plugin for you platform. This approach makes Phonegap a very fast-growing and powerful community. Well done!

So, enough theory - let's feel how is it - to develop a mobile app with PhoneGap!

Part 2. Let's get to action!

Chapter 4. Installation


After few minutes of research I decided to run my first app on Android, as deployment process seemed to be very easy for a newbie, comparing to iOS(no need for licence, direct access to device, no VMs, as I use Windows etc).

So, first thing I done - went to official PhoneGap "Getting Started with Android" guide, which seemed like a perfect start. Oh, how far from essence was I...

After several hours of pain and suffering I found out that I was not the only one having problems with installation. As it turned out - there was a lot of tiny typos and mistakes in that guide(on Windows only, as they all seem to work on Mac), which a non-mobile developer wouldn't notice.

Important thing I realized is that most of the errors I got was Android-specific, not PhoneGap-specific. In Android context, PhoneGap is just a Java library, and piece of static contents - html css and js. All you need to run PhoneGap app when you have working android environment is to include this library in project and include js script in your static web-site.

Of course, in PhoneGap docs they should've warn web-developers about common pitfalls of installing Android environment, and test their guides better. But don't be angry at them - be angry at Android:)
So your main problem is setting up Android environment. Adding PhoneGap libraries is pretty easy. Just make sure you understand what's going on.

I was working with PhoneGap 2.2.0, maybe they fixed something for 2.4.0, but anyway this article was pretty useful for me. Although I recommend googling for newer versions.

Chapter 5. Development

And so I ran my "Hello, World!" with PhoneGap.
The code seemed pretty much like: on Java, and
on html side. pretty simple isn't it?

But it gets much more interesting when building something bigger then just a skeleton app. If you have ever dealt with Android emulator, you'd notice that it's extremely slooooow. It takes from 5 to 30 minutes(!!!) just to check if your changes applied correctly! And also it happens often that some part of build process fails for just really random reason. Don't believe? I wouldn't. But it happens.

"Ok", I thought, "then I can just develop and debug design and main functionality in browser and then simply move it into the app, there shouldn't be much difference, right?"
WRONG!
This approach lead me to a very unpleasant situation, where my beautiful, good looking, bug-free static website turned into an ugly monster when displayed as an app. Actually, randomly-broken-functionality ugly monster. But more on that later.

So, advice no1 - go get the device! (although on iOS build process seems less painful).

Now, when you've got the device your development process blooms in every way. After you made changes in code, it takes about 2-3 seconds to see them applied on device(just use right shortcuts) . I'd say it's feasible.

Of course, it wan't solve all your migration problems, but at least you will get them one by one and in time :)

So, the development process goes like this: you edit the code in Eclipse, when ready - press smth like ctrl+f11 to build and deploy app to a device, look at device to see the app and decide if you need to change smth more. And what if you got a problem and want to diagnose it? Well, let's talk about it.

Chapter 6. Debugging

Here I've got the bad news guys. There's no way to debug javascript code inside an app on a device as you've got used to. No f12, no f8, no "debugger;". But, everything's not lost, there are several ways to diagnose the problems.

debug in browser

It's not universal, but for debugging purposes you can open you app in browser and use beloved js debugger to find the problem. Although all phonegap-specific features won't work of course. It's not always easy to maintain your app both for device and for browser because of these things. Usually this approach is good at the beginnings, when you're building your main logic without dependencies on device-specific features, or when you're editing something unrelated to device.

console.log

PhoneGap environment gives you a way to transport debug messages from js to your Eclipse console via console.log() method.Although it's not a run-time debugger, this can come in handy sometimes. 



hehe, good old way, reminds me of debugging scripts on ie6. Code speaks of itself

weinre


weinre seems to be "official" PhoneGap debugger, according to url. It lets you navigate your html content as you dynamically update it. It has a similar interface to Chrome developer console, to give you impression that you're home:) Although it's a bit slower and less user-friendly then chrome debugger, it may save your day.

Let me put the magic out if weinre. Everything is pretty obvious - you put their script with your "unique" id into your html file(it's not unique - you just pick non-common description of your app to find it between all the others later). This script sends ajax requests with information about page html and all that stuff periodically to their server to specific url based on id you chose. Then you go to their server using your browser, specify your id and server periodically returns new information about changes in your original html document. Then weinre js logic displays the results in a friendly way. Easy as hell.

It's also funny to watch how many people currently use weinre with default id "anonymous" and expose all their data:) Yes, security IS the concern here, because all your logic is transported through third-party soft and publicly exposed to everyone who can guess you "unique" id.

And, as you may have guessed, your device has to be online in order to debug your app using weinre.

Chapter 7. Deployment

Deploying mobile apps is pretty different from deploying web apps. In web you usually had a web server with predefined ip address and/or DNS name, and users simply access you web site by typing your address in their browsers.

In mobile world people use things like AppStore and Google Play to download apps. And while putting an app to Google Play is pretty easy, AppStore may reject your app if it doesn't follow their guidelines. Knowing them and following them is another problem, but there's a conceptual concern going on on the internet about PhoneGap and AppStore. 

PhoneGap and AppStore

Thing is, one of the rules of AppStore is that you cannot use UIWebView to load remote website, as AppStore cannot control the content of this website and you can post whatever you want on it, including forbidden stuff. This takes us to a fair question - if PhoneGap is the website inside UIWebView, will AppStore accept our app?

The answer is not just yes or no. As PhoneGap officially says, apps built on PhoneGap are not banned on AppStore. Actually it makes sense, as PhoneGap app is not a remote website, but a local one and you cannot dynamically change its contents without going through AppStore. But this is not the final point. You sill have to follow Apple's guidelines. Apple has made a good clear statement about this:
If you’re coming from the web, you need to make sure that you give people an iOS app experience, not a web experience.
So you still have to know their guidelines and iOS app UX. Same with Android, Windows and other platforms you're targeting, although some of them may have weaker requirement for following them.

PhoneGap Build

To ease your deployment process PhoneGap introduced thing called PhoneGap Build. Its a cloud service, that lets you forget about transforming your html,css and js files into Android or iOS app file.

In other words, you can write code on any platform, in any IDE(don't bother with Eclipse, Visual Studio or Xcode), let PhoneGap Build handle build process for you, download apk, ipa or whatever file your platform uses, install it on your device(Android, iOS, iOS for adventurers) and see the result! Of course, it takes more then 2-3 seconds as opposed to Eclipse build. But still, when automated, this process can be pretty useful.

Also, I must note, that using PhoneGap Build is very intuitive and pleasant, good job done here.

Chapter 8. Experience


When it comes to reality, and you need to build some non-trivial app, deploy it to couple of devices, and then to maintain it later, you just think "never again". The fact is that there is soo much mysteries around these built-in browsers that you can hardly manage them all. I personally still didn't find an explanation to couple of bugs. And it can be a serious show-stopper for the business you're in. So expect surprises, they will come.


Another thing is that these browsers are usually slower. Why? Well, for example, on iOS Safari uses Nitro to compile javascript, which dramatically improves performance, but on built-in browser Nitro is turned off for security (and i guess political reasons). This was one of the reasons why facebook moved from html to native approach(btw here's a cool video about that).


Also, as I told before - you still have to know the guidelines of each platform and apply specific design for each of them, and it doesn't just mean that you turn rounded corners into square ones, it also means that you redesign your view drastically. Moreover, there are sooo many devices out there, each supporting/not supporting specific feature... Do you really think you can use "One size fits all" here?

So now cross-platform apps has weakened in their meaning. Functionality is still very similar, but a bit different. And this "bit" messes everything up. And here come the phrases like "By the time your app redraws its view on click, you can go cook a nice fresh lasagna", "PhoneGap is cross-platform. It doesn't work on all platforms the same way." or "Instead of dealing with N platforms you just have to deal with N+1", and its almost true.

Chapter 9. Conclusions

So, we've processed a whole bunch of information. Let's wrap it up.

The term "cross-platform mobile app" is a bit misunderstood. The application may work on any platform, but it won't, or at least shouldn't, be the same on all the platforms.

When using PhoneGap - you're trying to save time and money, and may even succeed, but remember that you're trading quality to gain this.

Building non-common solution with PhoneGap is a huge risk and will likely end up in a disaster.

Trying to build mobile app without knowledge of platform you target will end up in clumsy user experience.

PhoneGap is the best there is in its field. Don't try re-implementing it on your own, as you will face same major issues.

When Phonegap may come in handy:

  • You're building near-trivial, common-purpose app with built-in controls and nothing extraordinary
  • You're having time shortage and need to deliver some results asap.
  • You don't have any Android or Java developer to build native app
  • You need to support more than 2 platforms
  • You need to support a platform so deprecated, that PhoneGap APIs are better then native.

Last word to say - respect to people who try to integrate web technologies into mobile devices. I understand  and share you goals, but unfortunately, and it's absolutely not your fault, the result is not satisfiable yet.

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.