HTTP Headers, Web Apps and Mobile Safari

I found today that Mobile Safari, the browser bundled with the iPhone, has a very strange and annoying behaviour when it comes to web apps. In fact, when you “install” web applications with the <meta name=“apple-mobile-web-app-capable” content=“yes” /> tag in the “Home Screen”, the USER_AGENT header sent to the server is different to the one sent when you access the same app manually using Safari..

Here’s a test that proves this assertion: Create a server-side web app with your preferred language, and print all the request headers; for example, in PHP:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
        xml:lang="en" lang="en">
<head>
    <meta http-equiv="content-type"
            content="text/html;charset=UTF-8" />
    <meta name="apple-mobile-web-app-capable"
            content="yes" />
    <title>UserAgent</title>
</head>
<body>
<?php
foreach($_SERVER as $h=>$v) {
    if(ereg('HTTP_(.+)',$h,$hp)) {
        echo "<li>$h = $v</li>n";
    }
}
?>
</body>
</html>

Launch MobileSafari.app in either the iPhone Simulator or in your iPhone or iPod touch, and access the server-side script you created previously:

safari1

Add the application to your home screen, tapping the “+” button on the toolbar:

safari2

Now launch the application from your home screen, and this is what you see:

safari3

Compare the outputs (above, those from the latest iPhone Simulator, and below, those from my iPhone 3G with iPhone OS 3.1.2):

Safari:

HTTP_USER_AGENT = Mozilla/5.0 (iPhone; U; CPU iPhone OS 3_1_2 like
Mac OS X; en-us) AppleWebKit/528.18 (KHTML, like Gecko)
Version/4.0 Mobile/7D11 Safari/528.16

Home Screen App:

HTTP_USER_AGENT = Mozilla/5.0 (iPhone; U; CPU iPhone OS 3_1_2 like
Mac OS X; en-us) AppleWebKit/528.18 (KHTML, like Gecko) Mobile/7D11

This difference is only visible when the HTML generated by the server-side script contains the <meta name=“apple-mobile-web-app-capable” content=“yes” /> tag, which triggers this change of behaviour. Otherwise, the outputs are exactly the same. Most annoyingly, this behavior is not documented (at least not that I am aware of). This problem has already been spotted elsewhere (scroll down until you see the comment by DVO published on Jul 3, 2009 at 7:34 AM; thanks to my friend Bertrand for the link!).

This is not only weird, but it also might break libraries used to generate iPhone-ready websites out of existing web apps (by redirecting the browser using the information in the USER_AGENT header; for example, this is what happens with the current version of the Rails iUI plugin (which is why I found this behaviour :)

The lesson of all of this mess is this: if you have to test for Safari on the iPhone, do not use the word “Safari”, but rather use “AppleWebKit” and “Mobile”, to be sure of catching also the users who installed your application in their home screen.

Update, 2009-10-30: In particular, the line of the Rails iUI plugin that causes problem with this particular behavior is this one.