Monthly Archives: March 2014

The minimal-ui meta tag in iOS 7.1

Update: iOS8 removed the minimal-ui tag. And no, it didn’t implement the FullScreen API either. Lovely.


 

iOS7 brings us yet another meta tag to use – minimal-ui. You might be able to guess what it does – it hides the majority of the browser chrome when you load, much like when you scroll:

With and without minimal-ui

With and without minimal-ui

Try it out. It’s a welcome improvement, especially after Safari’s disastrous changes with the release of iOS7, and feels like a tacit confession that shutting off the ability to hide the navigation bar (as you could in iOS6) was a mistake.

It also fixes what is easily my least favourite part of the iOS7 Safari UI: stealing tap events that happen at the bottom of the screen to show the bottom navigation bar:

 

With minimal-ui, the only way to restore the bottom navigation bar is to tap the address bar at the top.

But…

This feels a little weird. Users are now going to have different UIs depending on what meta tag the site does or doesn’t have. If users can’t rely on tapping the bottom of the screen to bring up the bottom bar, why have that functionality at all? Surely it would be better to be consistent.

It’s also curious that Apple went to these lengths to create a new meta tag while still not supporting the JavaScript Fullscreen API. Many of the people looking to hide the browser UI are making interactive experiences like games, and being able to go full screen would be even better than minimal-ui – as well as being an actual cross-platform solution.

For now we’ll have to throw the Fullscreen API on the pile marked “Please, Apple. Please“, along with WebRTC and WebGL. But the minimal-ui meta tag is at least a start.

WebRTC DataChannels or: How I Learned To Stop Worrying And Flap My Arms

I had an idea. A stupid idea.

Screenshot 2014-03-07 10.16.50I had discovered that mobile browsers have JavaScript APIs for accessing accelerometer and gyroscope data and wanted to play around with the concept – I hadn’t seen them used in many places. So naturally my thoughts turned to creating a version of Flappy Bird where you paired your phone and computer together, then used the phone as a Wii-like controller to flap your arms.

Now, hear me out – it made sense. Sort of. After the meteoric rise and disappearance of Flappy Bird there were dozens of open-sourced clones out there. And a ‘flapping’ motion seemed like it would be relatively simple to detect. But there was a problem. How do I pair the computer and phone together? My first thought was to use WebSockets – so off I went. One npm install later I had socket.io installed on a server. Pretty quickly I had a system set up where the ‘host’ (that is, the big-screen device) is assigned a random number, and the ‘client’ (phone) prompts the use to enter it. Then it just takes a simple chunk of code to get them talking:

So far, pretty simple. Try it out! …and get very, very frustrated very quickly.

The latency is too damn high

You flap your arms. Anything up a second later the bird might do the same. So, why is it so slow? This is where WebSockets shows its weakness – it still relies on a central server to post messages between clients. And that central server is in Amazon’s data centre in Northern Virginia. Even from my desk in New York, the route there isn’t exactly simple:

doneI dread to think what it’s like in Europe. A better solution was needed. I started googling “peer to peer websockets” and discovered a Stack Overflow question that led me in the direction of WebRTC.

But WebRTC is for webcams

I’d read about WebRTC before, in the context of replacing Flash and Skype for video chats. In my ill-informed way, that’s what I thought the “communication” part in “real time communication” meant. But no – it also has a capability called DataChannels, which are exactly what they sound like: peer to peer data connections. You can do a variety of things with themĀ  like share files or instant message, but let’s focus on the very important goal of making this arm flapping game more responsive.

“Marco”

So, a utopian server-less future? Unfortunately not. WebRTC’s peer to peer communication can do many things – but find other peers is not among them. So we still need a server to match client with server – just like we’re doing with WebSockets.

For this, I turned to PeerJS – a combination of node-powered server and client-side JS library that wraps around WebRTC functions. So, at this point I have both socket.io and PeerJS running on my server, and socket.io and PeerJS client libraries on the client. Feels like a waste. So we should get rid of socket.io now, right?

“Polo”

Wrong. For two reasons:

  1. WebRTC DataChannel browser support is not great. Especially on mobile – Apple deserves a lot of shaming for not supporting WebRTC at all.
  2. Peer to peer connections are tricky. Maybe you’re behind a firewall, or maybe there’s a NAT in the way. With WebRTC you can use a TURN server as a proxy between two clients, but in our case we’re already doing that with WebSockets.

So, we’ll keep WebSockets as a backup. Negotiate the pairing with WebSockets, then ‘elevate’ to WebRTC if both clients are capable and accessible – as demonstrated in this pretty awful set of diagrams:

There’s an added benefit here: the server is only used to create connections. Once that’s done, the clients disconnect, freeing up server resources for other players. If at any point in that process the WebRTC route fails, we just keep WebSockets open and communicate through that.

Our simplified code is only slightly more complex:

So, try it out. I think you’ll prefer it. Faster reactions, fewer server resources used, happier users. Unless they’re using an iPhone, of course.

Postscript: The Source Code

If you want to take a peek under the hood at FlappyArms, all the code is on GitHub. It’s really messy for the time being (being a two-day hack project and all), but I’m still adding features to it, and I hope to get it tidied up along the way.

How many people are using your site offline?

Back in the mists of the mid-to-late 2000s, life was simple. Users had a keyboard and a mouse. They had a screen that was wider than it was tall and usually had a resolution of at least this by that. And they were online. Of course they were – how else would they load your page?

Nowadays nothing is sacred. People browse on their phones, turn them sideways, shake them, swipe, pinch, tap and drop them in the toilet. You have to accommodate it all (well, perhaps not the last one), but nothing is trickier than connectivity. Most of the time users are online. But sometimes they’re offline. I saw a guy on the (underground, offline) subway today, paging through some tabs he’d preloaded onto his iPhone. His experience wasn’t great – he tried loading up a photo from its thumbnail, but the full-size version wasn’t cached offline. He was looking at some related links, but couldn’t tap any of them. He closed the tab and moved onto the next one.

Now, I know what you’re thinking (apart from “wow, you creepily stare at people’s phones on the subway?”) – he should just download an app! Offline storage, background syncing – it’s the ideal solution. Except he wasn’t using one. Maybe it’s ignorance. Maybe he doesn’t like apps. Either way, we’re in the business of catering to users, not telling them that they’re wrong, so it got me thinking – how many people do this? Should I worry about this? I have no idea.

Getting an idea: the OfflineTracker

So, let’s track this. Where to start? Well, the good news is that browsers have implemented some new events on the window object – online and offline. They’re far from perfect. The only truly reliable method is to regularly poll a remote resource to see if you can reach it – like offline.js does. However, firing up a cell data connection every 30 seconds will drain a phone’s battery, and is A Bad Thing. So we’ll make do. I made a quick gist:

https://gist.github.com/alastaircoote/9350466

(in CoffeeScript, see it in JS if you like) with a concept for this tracking. It’s more of a proof of concept than production-ready code, but the general flow is this:

  1. User goes offline. We record the current date and time as the ‘start’ of our track, and store it in localStorage.
  2. User comes back online. We stop tracking, update the end time to be the actual end time, and run the function provided to send this data wherever we want it to go.

Now, there are a few holes in this. So, we also do the following:

  • Update the ‘end of tracking’ time every 30 seconds. In theory we should be able to catch any and all events that would signify the end of tracking, but we can’t (what if the browser crashes? What if the user turns off their phone?). So every 30 seconds we update the ‘end’ of the tracking, and save to localStorage. If all hell breaks loose, our numbers will only be up to 30 seconds off.
  • Hook into the Page Visibility API. This is an event that tells us when the user moves away from our page (usually by changing tabs). This is pretty crucial because it’s going to stop us tracking time when we’re offline and in an inactive tab.
  • Provide a callback to the save function. We’re dealing with bad connectivity – we can’t guarantee that our data will get saved correctly. So we don’t delete our tracking data until the function runs the callback provided.
  • Check on page load for any saved data. So when subway guy views your page offline, closes the tab and moves onto the next thing you can still recapture that data the next time he visits your site.

So, now you have the start and end times of user offline browsing sessions. What you do with it is up to you – maybe only 0.5% of your users access your site this way and you shouldn’t care at all. But maybe your user base consists entirely of cave-dwellers. Either way it would be good to know, right?