Offline First
Because internet connections can be flakey or non-existent, you need to consider offline first: write your app as if it has no internet connection. Once your app works offline, add whatever network functionality you need for your app to do more when it’s online. Read on for tips on implementing your offline-enabled app.
Overview
Chrome Apps get the following for free:
- Your app’s files—all of its JavaScript, CSS, and fonts, plus other resources it needs (such as images)—are already downloaded.
- Your app can save and optionally sync small amounts of data using the Chrome Storage API.
- Your app can detect changes in connectivity by listening for online and offline events.
But those abilities aren't enough to guarantee that your app will work offline. Your offline-enabled app should follow these rules:
- Use local data whenever possible.
- When using resources from the internet,
use
XMLHttpRequest
to get it, and then save the data locally. You can use the Chrome Storage API, IndexedDB, or Filesystem API to save data locally. - Separate your app’s UI from its data.
- Separating the UI and data not only improves your app's design and eases the task of enabling offline usage, but also lets you provide other views of the user's data. An MVC framework can help you keep the UI and data separate.
- Assume your app can be closed at any time.
- Save application state (both locally and remotely, when possible) so that users can pick up wherever they left off.
- Test your app thoroughly.
- Make sure your app works well in both common and tricky scenarios.
Security restrictions
Chrome Apps are limited in where they can place their resources:
- Because local data is visible on the user's machine and can't be securely encrypted, sensitive data must stay on the server. For example, don't store passwords or credit card numbers locally.
- All JavaScript that the app executes
must be in the app's package.
It cannot be inline.
- All CSS styles, images, and fonts
can be initially located
either in the app's package
or at a remote URL.
If the resource is remote,
you can't specify it in your HTML.
Instead, get the data using
XMLHttpRequest
(see Referencing external resources). Then either refer to the data with a blob URL or (better yet) save and then load the data using the Filesystem API.Note: Styles can be inline or in separate
.css
files.
You can, however,
load large media resources such as videos and sounds
from external sites.
One reason for this exception to the rule
is that the <video> and <audio> elements
have good fallback behavior when an app
has limited or no connectivity.
Another reason is that fetching and serving media
with XMLHttpRequest
and blob URLs
currently does not allow
streaming or partial buffering.
To provide a sandboxed iframe, you can create an <webview> tag. Its contents can be remote, but it has no direct access to the Chrome app APIs (see Embed external web pages).
Some of the restrictions on Chrome Apps are enforced by the Content Security Policy (CSP) which is always the following and cannot be changed for Chrome Apps:
default-src 'self'; connect-src *; style-src 'self' blob: data: filesystem: 'unsafe-inline'; img-src 'self' blob: data: filesystem:; frame-src 'self' blob: data: filesystem:; font-src 'self' blob: data: filesystem:; media-src *;
Specifying offline_enabled
It is assumed that your app behaves well offline. If it doesn't, you should
advertise that fact, so that its launch icon is dimmed when the user is offline.
To do so, set offline_enabled
to false
in the
app manifest file:
{ "name": "My app", ... "offline_enabled": false, ... }
Saving data locally
The following table shows your options for saving data locally (see also Manage Data).
API | Best use | Notes |
---|---|---|
Chrome Storage API | Small amounts of string data | Great for settings and state. Easy to sync remotely (but you don't have to). Not good for larger amounts of data, due to quotas. |
IndexedDB API | Structured data | Enables fast searches on data. Use with the unlimitedStorage permission. |
Filesystem API | Anything else | Provides a sandboxed area where you can store files. Use with the unlimitedStorage permission. |
Note: Packaged apps cannot use Web SQL Database or localStorage. The WebSQL specification has been deprecated for awhile now, and localStorage handles data synchronously (which means it can be slow). The Storage API handles data asynchronously.
Saving data remotely
In general, how you save data remotely is up to you, but some frameworks and APIs can help (see MVC Architecture). If you use the Chrome Storage API, then all syncable data is automatically synced whenever the app is online and the user is signed in to Chrome. If the user isn't signed in, they'll be prompted to sign in. However, note that the user's synced data is deleted if the user uninstalls your app. {QUESTION: true?}
Consider saving users' data for at least 30 days after your app is uninstalled, so that users will have a good experience if they reinstall your app.
Separating UI from data
Using an MVC framework can help you design and implement your app so that the data is completely separate from the app's view on the data. See MVC Architecture for a list of MVC frameworks.
If your app talks to a custom server, the server should give you data, not chunks of HTML. Think in terms of RESTful APIs.
Once your data is separate from your app, it's much easier to provide alternate views of the data. For example, you might provide a website view of any public data. Not only can a website view be useful when your user is away from Chrome, but it can enable search engines to find the data.
Testing
Make sure your app works well under the following circumstances:
- The app is installed, and then immediately goes offline. In other words, the first use of the app is offline.
- The app is installed on one computer and then synced to another.
- The app is uninstalled and then immediately installed again.
- The app is running on two computers at the same time, with the same profile. The app must behave reasonably when one computer goes offline, the user does a bunch of stuff on that computer, and then the computer comes online again.
- The app has intermittent connectivity, switching often between online and offline.
Also make sure that the app saves no sensitive user data (such as passwords) on the user's machine.