Background Notification Hack for iPad and iPhone Sites
Mobile browsers may look like desktop browsers, but their behavior sometimes is different and we need to understand them to provide the right user experience. In this post I’ll show you a trick to notify the user about an update while our website is on a background tab.This post is partially extracted from my book Programming the Mobile Web, 2nd. edition published in 2013 by O’Reilly Media.
If you have an iPad, let’s say you have your webmail open in one tab. When you want to browse to another website, you open a new one. That means your email will be frozen for several hours or even days and you will never get updates, until you go back to that tab.
As developers, this raises an important issue: Is there any way to update the content and notify the user while the tab is in the background?
UPDATING A BACKGROUND TAB ON IPAD
After making some research and testing, I’ve found a good solution compatible with iPad to notify the user of an update when the tab is in the background: our old friend, the meta refresh.
While it can be an annoying behavior from a user’s perspective when the page is active, the old HTML mechanism allows us to define a meta tag to reload a window automatically every n seconds. Some browsers, such as Safari on iOS, allow us to use this hack to automatically reload inactive tabs and keep them updated:
<!-- Updates the page every 1 minute -->
<meta http-equiv="refresh" content="60">
With this technique, the page will reload on the iPad and the inline scripts and the onload event will be executed in the background tab on every version of iOS. On iOS 5.x no other event or timer will be executed after the onload event until the user goes back to activate the tab. On iOS 6.x timers continue executing even in the background after an automatic refresh.
REFRESHING THE TAB ONLY WHEN IN BACKGROUND
The problem is how to remove the reload behavior when the page is the active tab and the user is using our website. Every time we set the content attribute dynamically in the meta tag, the browser starts counting again, so we shift the next reload hit. We can use this idea then to not refresh the page all the time.
To make the trick work on the iPad, we can start a chronometer that will shift the refresh meta tag n seconds on every execution. While the page is still active, our chronometer will be executed and the reload action will be shifted every n seconds. When the page goes onto a background tab, the chronometer will not be fired and the refresh meta tag will trigger, refreshing the page once. From iOS 6, after the refresh, the chronometer will continue executing pausing more reloads:
<!-- Updates the page every 1 minute -->
<meta http-equiv="refresh" content="60" id="metarefresh">
// iPad background tab notification trick
var mr = document.getElementById("metarefresh");
mr.content=mr.content; // Shift the reload operation
}, parseInt(mr.content)/2); // Every 30 seconds in our example
CREATING A BACKGROUND NOTIFICATION
iOS doesn’t support the Web Notifications API as BlackBerry 10, Firefox for Android, Amazon Silk 2.0 and Firefox OS.
Unfortunately, Safari for iPad doesn’t make use of a favicon in the tab UI so our only option is to use the title element to update the UI and capture the user’s attention. Therefore we can change document.title to send information to the user via the tab’s title.
Therefore, if we just execute a chronometer and update the title, it will just work after the background reload. For example:
var count = 0;
document.title = count;
In this example, the counter will start from scratch every time we move the tab to the background as it reloads once. We can use sessionStorage to maintain values between reloads.
Chrome for Android supports background execution directly; therefore these tricks are not necessary. Table 12-1 shows the background execution behavior in different browsers.
WHAT ABOUT IPHONE?
I’m not sure yet if this is good news or bad news: we can use window.alert from a background tab that was refreshed and it works! And this trick also works on iPhone where there are no tabs but background windows. But be careful, it’s a very intrusive dialog from a background tab or window. If it’s an iPad, changing the title for the tab seems like a better idea.
For iPhone or iPod touch we can then refresh the page and generate an alert dialog if there is something important we want to say. However, there is no way to automatic move the active window to ours; so the alert message should indicate that to see what’s happening the user should move to our window.
CHANGE THE TITLE ONLY WHEN IN BACKGROUND
In this example, the title is being updated all the time, even when the tab is in foreground. To change that, we need a way to separate foreground from background state after a reload. Without Page Visibility API it seems complicate. I have even tried with Animation Timing API, also known as requestAnimationFrame and even in the background, frames are being fired. At the time of this writing I couldn’t find an easy way to differentiate between foreground state and background after a reload state.
If you find a way, just add a comment in this post.
BUT IT DOESN’T WORK ON IOS 5!
The previous code works perfect on iPad with iOS 6.x but on iOS 5.x it’s a different story. Because timers don’t fire on iOS 5 after the reload, we need a different approach. The approach on iOS 5 is to just update the title when the page is being loaded and leave the meta refresh make its work every n seconds. In the count example, we can just use sessionStorage.
var count = sessionStorage.getItem("count")||0;
document.title = count;
In this case we don’t have the problem as in iOS 6+ and we can update the title only in the background.
TRY IT YOUR SELF
If you have an iOS device with you, just go to http://ad.ag/pdtdpw
MORE ABOUT TABS
On future posts I’ll continue talking about background tab management for mobile devices, including page visibility detection. If you can’t wait to that time, remember my book Programming the Mobile Web, 2nd edition has +750 pages on the topic :) This is a series of posts I’m publishing based on content extracted from that book.
(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)