Why Trigger.io doesn’t use PhoneGap – 5x faster native bridge

Firstly, our own native bridging technology is significantly faster – up to 5x on Android according to our testing below.

We wanted to design the best experience for web developers to create native mobile apps by having:

  • a super fast build-test cycle
  • no need to write any native code,
  • no need to setup your environment for local compiles,
  • no need to setup XCode and Eclipse

These design constraints mean that our approach includes a ton of small differences from PhoneGap, not just in our native bridge but in the code around it to provide the best possible API and best possible build process for developers coming from web technologies.

We’re not averse to using existing solutions, and working to promote them and improve on them, where it’s right for our customers (our Catalyst debugging tool is a hosted build of Weinre). PhoneGap is a great product with lots of flexibility to write your own platform-specific native code in conjunction with HTML5 (which is not something Trigger.io offers). Strobe and appMobi both decided to use PhoneGap rather than developing their own native bridge.

Performance

Speed is a big concern for developers considering HTML5 and hybrid frameworks as opposed to native. So how does Trigger.io’s native bridge perform in practice?

On iOS, compared with PhoneGap we saw that our bridge performed at a similar level to PhoneGap with a small increase in speed:

Performance results on iOS

Performance results on iOS

On Android it’s dramatically faster:

Performance results on Android

Performance results on Android

To test both native bridges we created a PhoneGap plugin for both Android and iOS which immediately responds to any call with the data sent to it. This allowed us to send varying amounts of data from JavaScript to native and back again. We also added an equivalent method to our own API. Adding a new method which does no processing means we can more accurately test the bridge itself rather than a particular API method. If you want to see the source code used for this benchmark you can find it on github.

How Trigger’s native bridge technology works

Since launch, we’ve been asked about how our bridge technology works. Our architectural approach has much in common with PhoneGap’s – but with some differences that reflect our different priorities and ways of thinking.

Here’s how it works.

Wrapping and bridging to native

Our native bridge is what allows your JavaScript code to communicate with native code, in a way that’s consistent across platforms. For mobile platforms, your code is outputted into a WebView / UIWebView mobile browser frame, and our wrapper grabs your API calls and ‘translates’ them as appropriate for each platform on the fly.

We deal with iOS and Android  in different ways:

iOS: JavaScript to Objective-C, and back again

To talk to native code from JavaScript, we take your API call, serialise and store it temporarily in the DOM. We then make a request to a fake URI (forge://…) which we intercept in native code – allowing us to read in and act upon the API call stored in the DOM.

To communicate from native to JavaScript, it’s no problem: iOS gives us an API called

UIWebView.stringByEvaluatingJavaScriptFromString

which lets us execute JavaScript directly in the context of the UIWebView.

PhoneGap use a similar method, which explains why our performance is comparable in the benchmarking we did.

Android: Java to JavaScript, and back again

Java on Android provides an interface for Javascript to access Java methods directly, the opposite way round to what can be done in Objective-C. We use this method to pass API calls from Javascript back to native code – PhoneGap used to use this method but now avoid it. Instead PhoneGap use Javascript prompt boxes which they intercept in Java and prevent the user from seeing. This approach is heavier and hackier, but a decision they made in order to sideline a bug in the Android 2.3 simulation. It’s not a bug that affects actual Android 2.3 devices, so we take this to be a bit of overkill.

For Java to Javascript communication we can cause Javascript methods to be called (but not get access to any data they return) using the following code:

WebView.loadUrl(“javascript:alert(‘Hello World’);”)

Using this we can tell Javascript that there are responses waiting to be returned from Java and use the more efficient Javascript to Java interface to transfer the data. An issue with the loadUrl technique is by default it will close the keyboard if the user is currently entering text – something which is very annoying if you happen to make an API call in the background. We managed to work around this issue by preventing Android from closing the keyboard while an API call is made. PhoneGap instead run a local HTTP server on the device in Java, and send JavaScript requests to that server. We find that approach too heavyweight, especially as on devices with a proxy configured it has to resort to polling every 50ms, a very inefficient method.

In practice: calling native functionality from JavaScript with Trigger

How does this look in practice? You don’t need to worry about what the bridge does – you simply call native functionality in through our Forge API (the full details of which are in our documentation).

Here’s what happens when you run a command to access the native camera:

Native bridge flow

Native bridge flow

Conclusion

We aim to keep our framework as lean as possible and making the development environment and build process simple. We want the start to finish of cross-platform app development to be as straightforward as standard web development.

As a result we opted to build our own, faster bridge to native, for more responsive apps and fast development.