Since the onset of app stores, we web developers have been looking for a way to make our web sites look more “appy”. Browser makers have been giving us tools to make that happen. First, apple started supporting a few meta tags that filled the gab for web apps, allowing web apps to be “added to home screen” and then optionally, dropping the browser chrome, setting a custom icon and adding a loading splash screen. To do this, we simply added a few meta tags to the page:
<meta name="apple-mobile-web-app-capable" content="yes"> <meta name="apple-mobile-web-app-status-bar-style" content="black"> <link rel="apple-touch-icon" sizes="72x72" href="/apple-touch-icon-72x72.png"> <link rel="apple-touch-icon" sizes="114x114" href="/apple-touch-icon-114x114.png"> <link rel="apple-touch-icon" href="/apple-touch-icon-57x57.png"> <link rel="apple-touch-startup-image" href="/splash-startup.png">
Well that was fine in dandy, but that was only supported by iOS, then later, google added similar ones:
<meta name="mobile-web-app-capable" content="yes"> <link rel="icon" sizes="72x72"href="/icon72.png"> <link rel="icon" sizes="114x114"href="/icon114.png"> <link rel="icon" sizes="192x192"href="/icon.png"> <link rel="icon" sizes="57x57"href="/icon57.png">
The IE 10 came and added specific meta tags for it’s “pin” to start page:
<meta name="application-name" content="my app"/> <meta name="msapplication-TileColor" content="#000000"/> <meta name="msapplication-square70x70logo" content="tiny.png"/> <meta name="msapplication-square150x150logo" content="square.png"/> <meta name="msapplication-wide310x150logo" content="wide.png"/> <meta name="msapplication-square310x310logo" content="large.png"/>
Do you see where we are going with this? It gets old quick. The good news is there is a solution around the corner. It’s called the Manifest for Web Apps, and it allows you to collect all these features in a single, standard, JSON object (a manifest file). Add the single file to the head of your document:
<link rel="manifest" href="manifest.json">
And now life is simple right? Well it will be once all the browser support it. At time of this article, Chrome 38+ for Android is the only browser that supports the feature, but don’t worry, there is a pretty simple polyfill that makes it work on all mobile and some desktop browsers.
Building the Manifest
The manifest itself is a very familiar looking JSON object:
{ "name": "Super Racer 2000", "short_name": "Racer2K", "icons": [{ "src": "icon/lowres.png", "sizes": "64x64", "type": "image/webp" }, { "src": "icon/hd_small.png", "sizes": "64x64" }, { "src": "icon/hd_hi.png", "sizes": "128x128", "density": 2 }], "scope": "/racer/", "start_url": "/racer/start.html", "display": "fullscreen", "orientation": "landscape" }
Most of these values are straight forward:
- name: Name to show up in app listing or with icon
- short Name: when present used instead of name along with app listings
- start_url: when you click the tile or image, this is the URL that is launched (can be relative or full url)
- display: determine how the app should be presented to the user. Options are fullscreen, minimul-ui, standalone, or browser (opens in browser)
- orientation: default the app to a particular orientation as defined in the screen orientation API. Options are: “any”, “natural”, “landscape”, “portrait”, “portrait-primary”, “portrait-secondary”, “landscape-primary” and “landscape-secondary”
The other two values are a bit more complex, so you may need to break them down a bit more:
Icons is an array of objects that hold the characteristics for images used by the app presentation. Each object can have a few different values:
- src: this points to the location of the asset, the manifest will point to the path in the src, whether it contain a file extension or not. src can also be used to determine file type. Again, this path can be either relative to the url from which the manifest was fetched or a full URL
- type: determines the type of the icon file. If file extension is not present in the src, type will be determined by type (still trying to see the value of this one
- sizes: this declares the image size. As each platform can and does require its own unique file sizes, this allows the user agent (browser) to determine which images it can use, and which ones it ignores
- density: this is the device pixel density for which the icon is intended. If omitted, the user agent assumes 1.0
The final vale us a newer one to the spec, which is that of “scope” or navigation scope. The scope does two important things to maintain the “app experience” we are looking for as developers.
- Navigate outside the app: if you navigate to a URL (like click on an anchor) that is outside the scope of the app, then it will open that page in the standard browser (whatever your default browser is, even if it’s a different one).
- Navigate into the app: this is what we call “deep linking” when it’s to a native app. But if you navigate to a URL within the scope of the manifest , that URL will be opened inside the installable app context. This means a web page, or even native app can open up your fancy web app.
Serving the manifest
Serving the manifest should be fairly simple. As mentioned previously, it gets added to you web site with a link tag like so:
<link rel="manifest" href="manifest.json">
It can point to a file on the same domain or even come from a totally separate domain (following CORS policy of course). It is important to note that the file must be served with a specific content type. In this case it should be “application/manifest+json”. As it’s early in the implementation, it’s tough to tell how picky each of the browsers will be on the file type, but it’s a good idea either way.
I use an IIS server, where setting the content type is quite easy. For IIS, you simply add the below block to the configuration section of your web.conf xml on the root of your server:
<system.webServer> <staticContent> <remove fileExtension=".json"/> <mimeMap fileExtension=".json" mimeType="application/manifest+json"/> </staticContent> </system.webServer>
Final Thoughts
Making your web site more of an app experience is fairly simple, and can have quite an impact for users, especially as the Manifest for Web Apps spec moves forward to implementation, and until then, use the fantastic polyfill called ManUp.js written by yours truly.
One final thought: this format needs expand to specifically call out Hosted apps as well. The myriad of formats for stores is what makes the hosted apps difficult to build and maintain. I’ve already moved my tool called the Web App Template to this format, and it works really well for the developers who use it. Let’s move that forward and make it easier for us to submit our cross-browser web apps into the landscape of app markets.