In my previous article, I took a look at the "core" set of PhoneGap/Cordova plugins and how well (or how poorly) they are supported now via web standards. The idea wasn't to say you never need go hybrid, but that you may not necessarily have to go hybrid, which was one of the core principles behind PhoneGap in the beginning.
Every year we see browsers advance farther and farther, so let's continue to take a look at the remaining plugins and see how well you can by without them in 2017!
The Geolocation plugin provides access to the user's current location as well as their heading and speed. This is – I believe – the plugin that most accurately matches the "real" web standards API, to the point that if you know how to use the plugin, you are 100% ready to leave it behind. The only real difference would be in the prompt the user gets when using it.
In a web app, the browser will prompt with the full URL of site requesting permission:
In a Cordova app, the prompt will use the name of the app instead. The UI is a bit different too. I won't say it is better or worse, just a bit different.
But the crucial bit is that your code can literally be copied and pasted. Geolocation is also one of the most widely supported APIs out there:
One thing to note though – and this is a general trend for many of the more powerful APIs – you will be required to use this code on a https server in production. When running locally, a non-secure server is fine, but you will be prevented from using the API if you go live with http instead of https. (But we're all using https now, right?)
Simple – just use it. Out of everything I've covered in this series, this transition will be the easiest since the API just plain works the exact same going from the plugin to the web based API and support is incredible. Winner winner, chicken dinner!
The Globalization plugin provides support for developers who need to offer their apps in different locale. To be clear, this isn't necessarily something as complex as an English app being prepared for the Chinese market. It could be as "simple" as supporting Americans and Canadians. There is a lot more to globalization than language.
Consider this date:
What date is that? If you're an American, you probably assume April 8, 1973. For a majority of the planet though, that date would represent August 4th, 1973. That's a pretty crucial difference.
Numbers also change, although the impact is (possibly) less severe. For example, in some countries the thousands and decimal place characters are swapped, so 1,000.90 would be 1.000,90. I'd be willing to bet though that most users may not notice the swap. Still though, it's different and helping your users understand what they are seeing in your app should be an important concern.
You've got a couple of replacements for this in web standards. Luckily, the best replacement is the Intl spec (the hard core full spec may be read here but I'd go for the gentler introduction over on the Mozilla Developer Network). Intl provides similar functionality to the plugin and, in my opinion, is much easier to use. For starters, it's synchronous, which I know is a dirty word now, but, when we're talking about formatting, I have a hard time accepting that asynch makes sense. You also have pretty decent support:
As you can see iOS was a bit late to the party but, on the flip side, iOS adoption rates for new versions is pretty incredible. If you want to use a library, you could look at MomentJS's i18n support as well.
With Intl support being so high, I'd just use it and provide a fall back to no locale formatting in cases where it isn't supported. Note that we're talking about date, number, and currency formatting only. No API will automatically translate your text. While services exist, they should be used for the initial draft only and replaced with text handled by human translators. Finally, while it is a few years old, I wrote a simple introduction to Intl here: Working with Intl.
The InAppBrowser plugin is, as the docs say, a drop-in replacement for
window.open, which means there's no need for any code changes. The plugin, however, supports different options in regards to the new window versus what the web standard supports. (See MDN's reference here.) For example, the Cordova plugin supports a mediaPlaybackRequiresUserAction setting which requires user action before any HTML5 video/audio plays. In general though the basic idea of opening a new web page such that folks can still use your page works fine.
window.open is really old tech, it should just plain work. My only real advice would be what I'd tell to anyone opening new windows in apps: use with caution. In general, I prefer to open new windows (well new tabs) by my own choice. So I'd suggest perhaps using this minimally. I also like it when sites use some kind of visible marker to warn you that clicking on a link will open a new window.
Let's discuss the Media and Media Capture plugins at the same time, as they are so similar. The biggest difference – broadly – between these two plugins is that the Media Capture plugin relies on the default device apps for recording media (audio, video, and images) whereas the Media plugin requires you to build your own recording system. For example, it provides a
startRecord method, but you have to build your own button to fire this off as well as stop it. Also, the Media plugin only works with audio, not video or images.
Audio is a bit trickier. Using an input tag, you can use
capture="microphone". On my desktop test, the browser requested audio files, but did not fire up a way to record new audio. On iOS, it did not prompt for a new sound recording.
The Media Devices API mentioned in that previous article supports requesting audio only, but with the issue of limited browser support. You could look at the older getUserMedia as a fallback for non-Chrome/Opera/Firefox platforms.
So for video and images I think the recommendation stays the same – lean more towards the input tag. For audio, you will probably need to shift between MediaDevices and getUserMedia depending on your platform.
The Network Information plugin primarily does two things. First, it provides events for when a device goes off and online. Secondly, it provides an estimate of the connection speed. That estimate could be useful for determining if it makes sense to transfer large blocks of data or save it for later. As the docs for the plugin state, the code is based on older version of the network information API. But how far away from current standards is it?
In terms of listening for the events, you simply need to change from listening on the document object to listening on the window object. So this:
Support is pretty much 100%:
There is also a
navigator.onLine property that can be used to check the current status. But be aware that as the MDN documentation warns, a machine may be connected to a network – like office WiFi – and not have a connection to the internet.
On the other hand, information about the speed of the connection isn't going to be easily available. There is a new API to support this, Network Information, but support is practically nonexistent.
There are workarounds though, with the primary one being to load some image of known size and see how long it takes to load. This Stack Overflow post provides a solution based on that idea.
Absolutely, 100%, make use of the online/offline events to make your application aware of when it goes offline. Being able to work offline is one of the core tenets of Progressive Web Apps, and luckily browsers have great support for client-side storage to help with this. While support for other aspects, like service workers, isn't universal, adding this just improves the durability and usefulness of your application in general. Just. Do. It.
As a quick aside, Chrome has had network throttling in dev tools for a while now, but only recently did they support throwing the online/offline events when those values were used. That works great now, which means that, if you want to test, you don't have to turn your WiFi off on your machine.
Speaking of PWAs, the Web App Manifest standard supports supplying both splash screen and status bar (well toolbar) values for apps launched via a home screen (and desktop too, I believe).
If you're going the PWA route then you need a manifest anyway. If the idea of a splash screen is something you like, then this is pretty much the only way you can do it. You could build a loading page, which a lot of old Flash-sites did in the old days, but I'd argue against that unless you really, really need some time to load data for your app before it runs.
The Vibration plugin API is nice and simple. You tell the device to vibrate for a timeframe and that's it. You can also vibrate based on a pattern if you want to drive your users crazy.
The Web API version of this (as documented here by the fine folks at MDN) follows the same API. Unfortunately, support is next to nil now. I can't find it at all on CanIUse.com and the MDN link above basically shows it in few places and prefixed. It did "work" on my desktop Chrome and, what's cool is (and this is documented), if the API exists but is run on hardware that can't actually vibrate, it doesn't do anything bad. It just does nothing.
It would be pretty trivial to check for
navigator.vibrate and, if it exists, make use of it, but you should expect little to no support for the moment. As it's harmless either way, use if it you think it makes sense. However, when it comes to things like this, I always tell people to imagine the notification firing 100 times – an hour – and see if you really thinks it makes sense to use it. If so – go ahead. Otherwise, err on the side of not being so "loud" with your users.
The Whitelist plugin is all about controlling the assets your application is allowed to load. For applications that aren't very dynamic, this may not necessarily be very helpful, but, as in all things security related, it's pretty much always a good idea to err on the side of caution.
While the whitelist plugin is mostly concerned with the config.xml file used for Cordova applications, you should make use of CSP declarations in your HTML to get the same support. CSP, or Content Security Policy, is a way to define from what other domains resources can be loaded. For example, imagine on my blog (raymondcamden.com) I add a bit of HTML to load an image from some other domain such as
<img src="http://www.cnn.com/cat.jpg">. The CSP is what says, "Should I allow an image resource from cnn.com to load into this page?"
A CSP gets extremely specific. You can have one rule for images, one for CSS, and yet another for scripts.
The Content Security Policy Reference is a great place to learn more. Also note that Chrome does a dang good job of reporting issues with CSP and will be very useful when testing.
CSP has decent support and, as I said above, tooling in Chrome does a great job of pointing out any issues you run into. I'd suggest starting off using CSP in your HTML pages and make it part of your site template.
So is it time to give up on apps and just use the web for everything? Heck yes! Heck no! And with that, I've probably angered everyone, which is the point of any good article, right? Honestly, I enjoy building apps with the web. Hybrid let me get onto mobile and let me do things I couldn't do with vanilla web pages. It wasn't perfect, but it was much more approachable (to me) than native and I was able to deliver great results.
When mobile, and the app ecosystem (ugh, I kind of threw up a bit writing that) exploded, I'd say that most of what people wanted required native. Not all the time – there were plenty of apps that could have been done with the web, but, in general, what people wanted leaned more towards native.
Now it feels like things are shifting dramatically. The web can do a heck of a lot more, and I think folks are getting a bit tired of apps in general. As someone who loves the web, I think this is good overall and better for consumers in the long run. I don't think we'll ever see a time when 100% of what we want to do can be done with the web, but I think we're very close to the point where native will be the exception, and not the norm.
As someone who has been involved in the web for over twenty years, I have never been more hopeful, more excited, and just generally more confident of my decision to bet on the web. It is certainly not a perfect a platform and we are not yet in a state where we can always skip native, but every month the web grows in power and capability.
I'll leave you with this great announcement from the PhoneGap team:Moving Forward. In this post, Simon MacDonald details their plans to help migrate all existing plugins to fully comply with the latest web standards. This is an awesome effort and I fully encourage people to help them!