Note: I’ve been working on preparing this content for 2 conferences I’ve delivered on this topic. One was in Ukraine for the Item 2018 conference (video here) and one was during the French MS Experiences 2018 event. As the feedback was positive and as people asked me for written content to share, I’ve decided to write this article. It’s also my very personal point of view I’m sharing. I’d love to discuss about your own point of view, feedback and experiences in the comments section!
Let’s start by the life of a front web developer today. It looks like this (mess?):
And it’s just a slice of what exists today. Obviously, you can’t know all those frameworks & tools. There isn’t a specific combination to rule them all neither. You will have to make a choice based on your preferences, needs, projects requirements and existing skills set of your team members. But the good news is whatever the stack you may have chosen, it’s a web stack. This will provide you additional benefits for cross-platforms support.
Let’s start by the obvious and main solution you should think of: Progressive Web App or PWA. If you still don’t know what a PWA is, here are good resources to read/watch:
– Our main entry point containing tons of good resources: https://developer.microsoft.com/en-us/windows/pwa
– Building Progressive Web Apps during BUILD 2018 by Jeff Burtoft
– Progressive Web Apps on Google Developers
– Progressive web apps on MDN
In a nutshell, a PWA is a web app using the latest available features to match as close as possible a native app. For instance, it can be installed on a desktop/mobile, will work perfectly offline and should use a modern UI approach. As it’s based on standards, it works cross-platforms on Windows, Mac, Android, iOS and could even fallback in any web browser on your Smart TV for instance!
The minimum viable you need to implement to start claiming you’re building a PWA is:
– HTTPS. A PWA must be served over a secure channel.
– Web App Manifest. A small piece of JSON describing how your PWA should behave or how to install it.
– Service Worker. The core part of your PWA enabling a true offline scenario as well as boosting the performance of your web app.
I already covered in a previous article how PWA Builder can help you building this manifest and how I’ve been implementing it in my own PWA: Service worker, manifest and icons to make it a PWA.
By the way, my PWA, which turns out to be a WebGL/WebVR game, is available there: https://aka.ms/applescrusher. You can load it in any recent browser or device.
Note: you can read the full article: Using WebGL and PWA to build an adaptive game for touch, mouse and VR devices if you’d like to know how to build a similar PWA game.
If you’re opening my PWA on an Android device, you will have a similar experience as shown in this video:
You’ll see I’ve decided to use a display property set to standalone. This will remove the border UI (the “chrome”) of the browser when the app will be launched from the home screen. The experience will then be different than the classical one you have inside the browser. I’m also forcing the orientation to be set to landscape. This is very useful in the case of games as the gameplay is often optimized for a specific orientation. Today, the usual trick is to use a media query to ask for the user to rotate the screen. You’ve probably already seen that. Thanks to the Web App Manifest, you can be sure that your app is using the right orientation directly.
Based on your application’s logic and targeted experience, you have several possible strategies to manage the service worker’s cache. PWA Builder is providing various service workers ready to be used. You will probably have to adapt their code to perfectly match your needs, but it’s a good starting point.
As explained in my article, in my case, I’ve coupled a service worker with the usage of IndexedDB. The idea is to provide an offline experience that should be available just after the first complete load of the web page. Thus, if you manage to load my game on your mobile just once, even by switching to airplane mode immediately after, you will still be able to reload it. Just like a normal native app you would have installed from a store. In my case, the first load could be considered as the downloading process of an app from a store.
To highlight the result, I’ve done this second video to show you that this is working as expected:
As you can see, even without any network connectivity, the game can still be loaded from the browser. The service worker is getting the application files (JS, HTML, CSS and images) from its cache while the game engine is taking the game’s 3d assets from IndexedDB. I’m pretty proud that the IndexedDB layer I’ve written years ago for Babylon.js is still totally relevant for PWA 🙂
We just covered some of the main benefits provided by PWA via this use case. But there’s now a lot of PWAs out there on the web, and they have interesting feedback to share. For instance, if you go on: https://www.pwastats.com, you’ll learn that the PWA version of Twitter has managed to create a better user engagement.
And you’ll see several other great testimonials like this one.
However, even if the web platform has done impressive progresses in term of features exposed, there are still some limitations compared to native apps. This web site is interesting to give you an idea: https://whatwebcando.today/
As you can see, you can’t have access to NFC for instance. To go beyond this barrier, there are several possible solutions, the cross-platforms ones are exposed after.
Our main documentation entry point on PWA for Windows 10 is: https://developer.microsoft.com/en-us/windows/pwa. Please read our documentation explaining how this works: https://docs.microsoft.com/en-us/microsoft-edge/progressive-web-apps/get-started.
Some of our partners have published their app using this approach such as Twitter.
PROs & CONs
So, what are the PROs & CONs of a PWA you need to have in mind when you’ll think of your new app.
- It’s just a web site!
- Easy updates on the web server
- Same code everywhere
- High reach / Any device
- Same UI/UX on all platforms
- Don’t (always) have a full access to the platform / hardware
Indeed, even if you’re submitting your app to the Windows Store, the updates will be done on the web server hosting the PWA and will be immediately reflected on the user’s device. You will have to go through the validation process the first time, of course, but future updates will be much faster to push to the device than an update of a classic native app where a new package has to be pushed every time. If you don’t publish on a store, well, it’s just a web site again. Web is offering by far the highest reach possible today as every device has a web browser. It’s also easy to be indexed by search engines. Deep linking is part of the web whereas it could be something difficult to implement in a native app.
Of course, not everything is perfect using a PWA approach. You will have the very same UI/UX on all platforms. If you need to differentiate the UX on a specific platform to embrace its specific design language, this is not something easy. Also, as discussed before, you won’t always have a full access to the platform. If your app must discuss with a USB device for instance, this could be a blocker.
So, what are the options to resolve those cons?
You probably already used an Electron app without knowing it.
Visual Studio Code, Microsoft Teams, Slack, Skype or Discord are all based on Electron for instance, to name a few. You can view an exhaustive list of other apps using Electron here: https://electronjs.org/apps.
So why Electron is so popular and what does it offer? Electron can package your existing web app, which could already be a PWA by the way, and extends it on the desktop to break the barriers discussed in the previous section. It targets desktops only: Windows, MacOS & Linux. Electron can’t target the iOS or Android devices.
Electron is packaging your web app alongside with the full Chromium and Node.js binaries. It means that every time you’re installing an Electron app, it installs a full copy of Chromium and Node.js with it.
Note: Electron is a project created and maintained by Github. As Github has been acquired by Microsoft, it turns out Electron is a Microsoft project in a way now 😉
There used to be some important delta between the version of Chromium shipped with the Electron project and the official Chrome release. This has been reduced recently. For instance, the Electron 3.0 stable release has shipped in September 2018 with Chromium 66. You can find more recent releases of Electron shipping Chromium 68 or 69. Still, Electron is usually a couple of months behind the latest public builds of Chrome/Chromium. It means that you won’t be able to ship a code using the very latest features shipped with Chrome inside an Electron app. Keep that in mind. But you will just have to wait for a couple of weeks/months before it becomes available in the Chromium version shipped in the Electron branch.
An electron app can better integrate the desktop environment. As explained in their doc, you can set the recent documents, manage notifications or drag files out of the window for instance. You can also have access to the file system via Node.js as explained in this doc: Electron Application Architecture.
On my side, I’ve decided to check, for fun, how far I could use Electron to create a copy of the default installed Calculator app which is written using UWP/XAML. First of all, to achieve the Fluent Acrylic effect / blurry background, I’ve found this NPM package: windows10-fluently-vibrancy for Electron apps.
Using the latest CSS features such as CSS Grid and Flexbox combined with some other tricks, I’ve managed to create something relatively closed to the design of the Calculator app. Look at this video comparing both versions:
So, who’s who?
The first one is the UWP version and the second one is the Electron prototype I’ve built. You’ll see I’ve been able to do the compositing effect with the background to create the acrylic effect and even managed to partly implement the reveal effect on some of the buttons. The background compositing effect is done thanks to a call to a native Windows API. This was to illustrate you how Electron could embrace some of the platform’s specifics.
So as you can see, you can use Electron to share your code as much as possible cross-desktops, but you can still use the platform’s API to do a great job integrating its design language.
PROs & CONs
Again, to help you deciding whether Electron could be a good choice for you, here are the PROs & CONs:
- Use your favorite web stack (front + node.js)
- Controlled browser’s engine
- Can interact with the system via native calls
- Linux / MacOS / Windows easy targeted
- Embed a full Chromium & Node.js
- Security updates of Chromium
- Desktop only
- Web UI
However, there are some drawbacks to these obviously. First, the size of your installation package. Indeed, you won’t rely on the already installed browser of the platform as you’re shipping yours inside your package. This also means that you’ll be responsible for updating the embedded browser. If a security issue is discovered inside the Chromium version you’re shipping, your app could be a security breach for the user’s system. You must pay attention to this whereas with a classical PWA, this is the responsibility of the browser’s vendor to update & maintain his product you’re running on top of. At last, Electron is not targeting iOS / Android mobile platforms, it’s desktop only. Still, nothing prevents you to ship it as a PWA for desktops & mobiles and package it as an Electron app to offer a more advanced version for the desktops. At last, most of the time you’ll implement the same Web UI/UX of a regular web app even if I’ve demonstrated that nothing prevents you from embracing the platform design language.
Hybrid web app
There are 2 options to build a hybrid app:
- Apache Cordova
- Your own native app with a WebView inside it
- XAML/C# or C++
- Swift / Objective C
- Java, etc
But if you use the second option, you will have to handle yourself the communication between the WebView and your JS code with the native code.
That’s why, the most obvious choice to consider is Cordova. You can learn more about Cordova: https://cordova.apache.org/ if you don’t know it yet. You’ll find some apps based on Cordova here: https://phonegap.com/app/.
Cordova is offering you a framework that will simplify the communication between your JS code living in the WebView and the native platform through plugins. Those plugins expose JS endpoints you can call from your code and then, the endpoint is making native API calls for you.
There’s a bunch of plugins available by default in Cordova providing various services like battery status, file access, vibration and so on. Features often not available in browsers. You can also search for existing plugins or write your own. The plugin must be written in the native language of each targeted platform: Objective C for iOS, Java for Android, C#/C++ for Windows, etc. So, writing a plugin requires specific skills.
Your web app code (HTML/CSS/JS), like Electron, can either be directly embedded in the app package or hosted on your web server.
You have 2 choices for the UI:
- Offer the same UI across all platforms as a regular web app or PWA
- Embrace the UI of the targeted platform
As we’re running inside a WebView, embracing the mobile’s UI experience using pure CSS/HTML & JS is not something simple. Even a simple iOS or Android slider could need a lot of a work to be built with HTML/CSS and to mimic as close as possible the native control.
That’s why, you can use another framework on top of Cordova to help you on this part too. A current very popular one is Ionic: https://ionicframework.com/.
It offers a set of controls that will change their look/behavior dynamically based on the platform they’re running on. It uses a modern web component approach via Stencil.js. For instance, here’s the sample code running on 3 different mobile platforms (iOS/Android/Windows):
You can see the UI is adjusted to match the design language of each platform. Still, you have a unique HTML / JS code to maintain on your side. Even if the UX/UI proposed by Ionic is impressive, it’s still not completely identical to the native controls. But honestly, it will do the job most of the time for your users.
You can find a list of apps built on top of Ionic: https://showcase.ionicframework.com/apps/top.
Please note that Ionic is also currently working on a new approach named Capacitor to move away from Cordova. It uses their own hybrid solution instead. It can target iOS/Android, Electron & PWA.
PROs & CONs
Hybrid apps is then another interesting approach for you to consider but what are their PROs & CONs?
- Can better integrate with the hardware / platforms via plugins than a PWA
- Can have a look & feel very similar to the native controls thanks to Ionic…
- … but it’s still not a pure native experience
Cordova is often used to target mobile platforms, even if it can perfectly address also desktops one. You can check their interesting platform status: https://cordova.apache.org/docs/en/latest/guide/support/. Compared to Electron, it doesn’t ship a unique browser engine (Chromium) but rely on the already installed platform’s WebView (Safari based on iOS, Chrome on Android, Edge on Windows, etc.). It can also make calls to the native platform and break some of the barriers of a regular PWA. Regarding UX, you can offer to your users a native-like UI thanks to Ionic.
Still, thanks to this approach, we can perfectly imagine having a PWA shared & extended across-platforms. A lot of the code, if not all, will be shared. Having a non-perfect mobile UX could totally make sense for your targeted users.
Up to now, we’ve found various ways to do calls to the platform APIs (Windows 10 PWAs, Electron or Cordova) but never managed to find a perfect solution for the UI part. Still, those solutions could be used to share almost 100% of the JS code as well as the HTML/CSS for the UI.
Today, 2 frameworks are using this approach: Telerik NativeScript and Facebook React Native. Both are very similar in their approach. The choice between one of them will be driven by your existing skills. You’re already using Angular or Vue? NativeScript will probably be a natural path. You’re a master of a React.js? React Native is the way to go. But again, there’s no absolute choice. You should evaluate deeply this approach as well as both frameworks implementing it before making your final decision.
If you’re a developer like myself, you probably already wonder how this magic works? Well, check out their doc: NativeScript – a Technical Overview.
You see that it will be translated to the appropriate Java or Objective C code. Something Electron is also offering, but in the desktops’ world.
Here are cool diagrams illustrating the execution flow in detail:
Let’s now see a video I’ve made illustrating their XML-based language to dynamically create native UIs on both an iPhone and Android phone at the same time.
The layout is described using an XML language you’ll have to learn. But it’s obvious, even more if you’ve already built native applications (XAML or Android are using XML approaches). The controls (Label, StackLayout or GridLayout shown in the video) are mapped to their corresponding native controls on iOS/Android. The structure of the project looks like an Angular one with .HTML, .CSS and .TS files. The styling of the native controls can be achieved via CSS. In the demo, I’m showing an Angular approach. This means that an Angular developer will be able to reuse his habits / skills building a NativeScript application.
Both phones are connecting to the NativeScript playground via websockets thanks to the QR code generated. Then, you can live edit the UI code in the browser and it will be reflected by instantiating native controls on the connected phones. As you can see, the sliders, switches, datepicker & calendar controls are offering the native & perfect UX of both platforms. There won’t be any difference from a native app on this side for your user.
React Web components are written in JSX. The props & states are bound to the DOM. Here’s a sample React Web component:
React Native components are also written in JSX. But this time, the props & states are bound to the native views. Look at the same component written for React Native:
It means that you’ll be able to re-use your React.js skills, but you’ll obviously have to rewrite to views for React Native to use the appropriate language for native components.
Some famous apps are built using React Native:
At Microsoft, we’re also using React Native for Microsoft Teams on iOS and Android. There’s an interesting article to read about Microsoft Teams architecture: Microsoft Ignite Live Blog – BRK3118 – Microsoft Teams Architecture: “The Teams client architecture shares a code base between Windows and Mac, which allows Microsoft to ship updates to both platforms at the same time. Also interesting is that Microsoft is moving from Angular to React for the desktop client. Angular was their choice back in the days, because that seemed the right choice then, but moving forward a shift to React provides code share possibilities between the desktop and mobile clients.”
PROs & CONs
- Rich Native UI & perfect platform integration
- Target iOS & Android with a unique UI code
- Need to learn the native controls / syntax
- Debugging can be much more complex than just hitting F12
- Less reach than PWA
This approach is currently very popular and has great positive aspects. But it still fairly new and feedback from teams / products using it should be read before going into this direction. For instance, the blog posts series of Airbnb is a must read: React Native at Airbnb. They’ve ended up moving away from React Native and they’re explaining why. Of course, you’ll find also very positive testimonials on the official React Native page such as the one from Pinterest: Supporting React Native at Pinterest. Our own Microsoft Teams group seems very happy with their choice.
I’d like to start by this sentence: “The Web is for audience reach and native apps are for rich experiences. Both are strategic. Both are valuable. So when it comes to mobile, it’s not Web vs. Native. It’s both.”.
Today, you can target both reach and rich experiences using web technologies. The web can now build high quality apps on any device.
To my point of view, PWA should be considered first. This is what I’m recommending to partners & customers I’m meeting during my Microsoft life. It has the highest reach, the highest portability and it’s now mature enough to be used in production without issue. Its full support is widely available, and the Progressive part will make it compatible with older browsers anyway. At Microsoft, we’re going to invest a lot into PWA in the future.
PWA has of course 2 major limitations: you won’t have a native UX and you won’t have a full access to the hardware / platform (except on Windows 10). If it’s a blocker, and if you’re an Angular/Vue or React developer, there are some interesting combos to investigate. Based on your specific needs, I would recommend one of those:
- PWA + Electron for desktop
There are the common patterns I start to frequently see. But again, there’s no absolute answer. You’ll have to first think about the UX you’d like to provide to your user, the level of portability you may need, the specific platform/native integration needs you may have. Finally, you will have to consider the existing skills of your team and the potential learning curve associated with a new technology introduced. But I’ve met several teams made by former C# or Java developers having switched to those approaches without specific difficulties, just after a couple of months of ramp up.
I hope this will help some you having a better understanding of what you can and what you can’t do today with web technologies. Feel free to share your own experience and feedback in the comments’ section!