Installing web apps natively

[2014-06-25] dev, javascript, clientjs
(Ad, please don’t block)

Web apps have been around for a while, but the ability to install them as if they were native apps is relatively new. This blog post takes a look at what’s currently possible.

Delivering and publishing installable web apps  

Web apps are called installable if they can be installed natively. Such apps are currently delivered in either one of two formats:

  • Hosted: the app is delivered as a collection of assets (HTML, CSS, JavaScript, etc.), hosted individually on a web server. Two associated files provide important meta-data:
    • App manifest: specifies information such as: the app’s name; links to icons; the path of the HTML file that is the entry into the app; etc.
    • Cache manifest: enumerates the assets of an app, enabling engines to download all of them and run the app offline.
  • Packaged: the app is delivered as an archive that contains all of its assets. The archive still contains an app manifest, but doesn’t need a cache manifest.

In order to publish a web app, to put it online, two options are common:

  • App store (sometimes also called “app marketplace”): You submit your hosted or packaged app to a central authority which makes the app available to the public. This service may be contingent on the app passing a review process.
  • Self-publishing: you publish the app yourself, via a server that you have access to.

Signing packaged apps  

The main reason for the existence of packaged apps is that it is easy to sign them via public-key cryptography: Each app developer gets a public and a private encryption key. Their signature is a hash of the package contents, encrypted via the private key. The signature proves who created the package and is validated by decrypting it with the public key and checking that the resulting hash is correct. The hash also ensures that no one has tampered with the archive.

The kind of signing that I have just described tracks developers, not apps. As a benefit, developers can sign and publish their apps themselves; there is no need to submit them to an app store. But this approach still enables several security measures:

  • If an app does something evil, browsers can blacklist and prevent the execution of all of its developer’s apps. That is, developers can be held accountable for their creations.
  • Signed apps are more trusted and get access to some security-critical APIs that unsigned apps are not allowed to use.
  • A web app’s data on a server can be encrypted via a developer’s private key, meaning that it doesn’t exist in the clear and is a bit safer from attackers.

Obviously, for maximum security and less technically savvy users, this approach can still be complemented by a curated app store where each app has been reviewed.

The state of the art  

Apache Cordova (on which PhoneGap is based) is the classic solution for turning web apps into native apps. Alas, it requires intermediate steps: building the native app and – often – submitting it to a proprietary app store. On the other hand, you do get comprehensive access to native APIs.

The platforms supported by Cordova are: Amazon Fire OS, Android, Firefox OS, iOS, Ubuntu, Windows Phone, Windows, and others.

The following subsections cover additional solutions, which often do not require intermediate steps to go from web app to native installation.

Windows, OS X, Linux  

  • Firefox: can create native apps from running web apps.

    • Both hosted and packaged apps can be either self-published or submitted to the Firefox Marketplace. It is also possible to run one’s own marketplace.
    • More information: “Quickstart – App Center” by Mozilla.
    • Trying it out: run the quickstart’s demo app in Firefox and push its install button to create and install a native app.
    • Current limitations: First, there can be at most one app per origin (domain plus port). Fixing this is in progress. Second, the only way to install an app is by running installation code from it (e.g. after a button has been clicked). In other words, there is no way to declaratively associate a manifest via a <link> element and let Firefox trigger the installation. Third, on OS X, you must use the context menu to open a native app for the first time (i.e., it is not natively signed and Gatekeeper initially prevents it from running).
    • Bonus feature: Firefox for Android can generate native Android apps.
    • Under consideration: there is an open ticket for supporting Safari-style meta-tags.
  • Chrome: So-called “Chrome Apps” can be hosted or packaged, but they can only be installed via the Chrome Web Store. Thus, self-publishing is not possible on Chrome.

    • Bonus feature: There are tools for turning a Chrome App into a native iOS or Android app.
  • Windows 8: allows you to write native apps in JavaScript, but many of the non-UI APIs are proprietary.

    • Bonus feature: web apps can customize their tiles.
  • Ubuntu: lets you write native apps in HTML5.

Other operating systems  

  • iOS: Users can add web pages as icons to the Home screen. In the app switcher, they appear as separate apps with custom icons.
  • Android: Starting with Android 4.0, Chrome contributes a powerful “Add to Homescreen” to the platform. It lets you install web apps so that they look and feel like native apps. (The corresponding feature of the stock Android browser is much less powerful and more like bookmarking.)
  • Windows Phone: You can add web apps to your collection or pin them to your start screen. But they appear as Internet Explorer during app switching and offline operation doesn’t always seem to work reliably.
    • Limitation: Configuration similarly cumbersome to Safari on iOS (but incompatible with it).
  • Firefox OS: Firefox-style web apps are the native apps.
  • Chrome OS: Chrome apps are the native apps. Again: apps can only be installed if they are in the Chrome Web Store.

A standard manifest format for web apps  

Currently, the manifest files used by Mozilla and Google are different. However, both companies recently agreed on a common standard. The following are two examples from the specification.

Example 1: a typical manifest.

{
  "name": "Super Racer 2000",
  "icons": [{
        "src": "icon/lowres",
        "sizes": "64x64",
        "type": "image/webp"
      }, {
        "src": "icon/hd_small",
        "sizes": "64x64"
      }, {
        "src": "icon/hd_hi",
        "sizes": "128x128",
        "density": "2"
      }],
  "start_url": "/start.html",
  "display": "fullscreen",
  "orientation": "landscape"
}

Example 2: linking to the manifest.

<!doctype>
<html>
<title>Store finder - search</title>

<!-- Startup configuration -->
<link rel="manifest" href="manifest.json">

<!-- Fallback application metadata for legacy browsers -->
<meta name="application-name" content="Store Finder">
<link rel="icon" sizes="16x16 32x32 48x48" href="lo_def.ico">
<link rel="icon" sizes="512x512" href="hi_def.png">

The future of packaged apps  

Apart from signing apps, packages could serve two more use cases:

  • They speed up downloading, because you need less HTTP round-trips to download the contents (as opposed to downloading files individually). A package format could replace current improvised techniques. Longer-term, SPDY and HTTP/2 will solve this problem, too.
  • They would also be useful for bundling content. HTML content usually comprises multiple files, which impairs portability. For example, to email such content, people often ZIP it and send it. Then the recipient has to unpack the ZIP file in order to access the content.

Alas, packaged apps as supported by Mozilla and Google currently have two problems:

  • There is no standard format for them.
  • You can’t access their content without unpacking them. Ideally, web browsers would handle them as if they were unpacked directories.

To fix these problems, Mozilla’s Jonas Sicking recently proposed four measures:

  1. Standardizing a package format that supports streaming and per-file meta-data.
  2. Introducing a Content Security Policy mechanism similar to “self”, but meaning “in the same package” instead of “from the same origin”.
  3. Enabling URL syntax for referring to files inside a package. This could look as follows: http://example.com/myapp.package!//img/logo.jpg (!// would separate the path of the package from the path inside the package).
  4. Standardizing the signing of packages.

Source of this section: “Future of packaged apps” by Jonas Sicking.


Reviewers of this blog post: