Hey everyone, I’m Laurent and this is my first post here. A lot of people have been asking us how we made the Front desktop app, so here it is.
So, what’s a hybrid app?
Though we sometimes go to great lengths to hide it, Front is actually an hybrid app: just a customized browser where we replaced all the interface. We get to design most of the interface with HTML/CSS and we add native code only for the things we couldn’t normally do in a browser (like accessing the file system). Regardless of the version you use, it shares 90% of its code with the pure-web version.
Why did we go for the hybrid app?
We’ve always wanted Front to run on the desktop. Though web apps (as in: apps running in a browser) have come a long way, a browser is still not the perfect platform to collaborate in real-time with quick-paced interactions. You need desktop notifications and a badge in the Dock to let people know about new things that happened during their lunch break. You also need to integrate deeply with the OS. With OS X, it means for example previewing files with Quick Look or registering global keyboard shortcuts.
The promise of hybrid sounds too good to be true: you get to build your app with HTML/CSS, which is usually faster than going full native. You can do very quick iterations with your design team (Front’s designer codes directly in the app). And, you can release it on every platform easily.
Of course, hybrid apps bring their own sets of problems. Their main problem is that they have had a tendency of looking alien: you instantly know that you are looking at an embedded website that you would rather use in a browser . Getting every little detail right takes a lot of time, and can ultimately cost more than going native.For Front, it was an easy decision though: the vast majority of emails are HTML and all modern email clients are just repurposed web browsers. Overall, we’d say that if you plan on experimenting a lot,* hybrid is the better approach* because it will allow you to make big changes very fast.
How do we make it work?
1. We decided not to use a runtime
Now that more and more people are building hybrid apps, runtimes have been released to do the heavy-lifting of embedding a browser and providing native APIs for the most common things (on the desktop, popular options include node-webkit, CEF and atom-shell). When we started about a year ago, we felt that the available solutions weren’t mature enough: too many open github issues to our taste and the embedded Chromium tended to lag a few versions behind. We eventually decided we would maintain a small native app for each platform we support.
2. And we built our own OS X app
The usual disclaimer applies: we’re a small team, it took us a while to learn all the things we’re sharing here, but it doesn’t mean there aren’t better, simpler solutions.
Front on OS X is a native Cocoa app but on a closer look, even if the tool bar is fully native, most of the real-estate space is taken by a giant WebView. Webviews are controls available to all Cocoa apps: they embed the rendering engine of the Safari that comes preinstalled with your Mac. This means we have to support multiple versions of Safari, but having the app sit at roughly 2Mb is a nice unexpected surprise that our users enjoy.
The first thing you want to do is be able to open the Web Inspector in your WebView. Open a terminal and run this:
Then, you will be able to right click anywhere in your app and hit “Inspect Element”. You want to get your WebView to talk with the native code. In our case, we’re trying to get an AngularJS app talk to Objective-C. If you bind your WebView to the web outlet, calling JS code from Cocoa is very easy:
Finally, inside the AngularJS, we just expose this facade:
The other side: calling native code from AngularJS is just a little bit more complicated. First, you need to create a NSObject with the methods you wish to expose:
Then, you need to implement 2 methods to whitelist the methods you want to be able to call:
Finally, you need to attach this object to your web view.
The webapp has an AngularJS module called desktop which is implemented differently for each platform. Here is
The name of Objective-C methods appears with a different name JS. The OS X Documentation explains how the conversion works.
That’s all for today! Let me know if you have any questions, would be happy to chat more on the subject. I’ve posted a small demo on my github to show off everything.