OLD | NEW |
1 <h1>Offline First</h1> | 1 <h1>Offline First</h1> |
2 | 2 |
3 | 3 |
4 <p> | 4 <p> |
5 Because internet connections can be flakey or non-existent, | 5 Because internet connections can be flakey or non-existent, |
6 you need to consider <em>offline first</em>: | 6 you need to consider <em>offline first</em>: |
7 write your app as if it has no internet connection. | 7 write your app as if it has no internet connection. |
8 Once your app works offline, | 8 Once your app works offline, |
9 add whatever network functionality you need | 9 add whatever network functionality you need |
10 for your app to do more when it’s online. | 10 for your app to do more when it’s online. |
11 Read on for tips on implementing your offline-enabled app. | 11 Read on for tips on implementing your offline-enabled app. |
12 </p> | 12 </p> |
13 | 13 |
14 <h2 id="overview"> Overview </h2> | 14 <h2 id="overview"> Overview </h2> |
15 | 15 |
16 <p> | 16 <p> |
17 Chrome Apps get the following for free: | 17 Chrome Apps get the following for free: |
18 </p> | 18 </p> |
19 | 19 |
20 <ul> | 20 <ul> |
21 <li> Your app’s files—all of its JavaScript, | 21 <li> Your app’s files—all of its JavaScript, |
22 CSS, and fonts, plus other resources it needs | 22 CSS, and fonts, plus other resources it needs |
23 (such as images)—are <b>already downloaded</b>. </li> | 23 (such as images)—are <b>already downloaded</b>. </li> |
24 <li> Your app can <b>save and optionally sync</b> | 24 <li> Your app can <b>save and optionally sync</b> |
25 small amounts of data using the | 25 small amounts of data using the |
26 <a href="storage.html">Chrome Storage API</a>. </li> | 26 <a href="storage">Chrome Storage API</a>. </li> |
27 <li> Your app can <b>detect changes in connectivity</b> | 27 <li> Your app can <b>detect changes in connectivity</b> |
28 by listening for | 28 by listening for |
29 <a href="https://developer.mozilla.org/en/Online_and_offline_events">online
and offline events</a>. </li> | 29 <a href="https://developer.mozilla.org/en/Online_and_offline_events">online
and offline events</a>. </li> |
30 </ul> | 30 </ul> |
31 | 31 |
32 <p> | 32 <p> |
33 But those abilities aren't enough to guarantee that your app | 33 But those abilities aren't enough to guarantee that your app |
34 will work offline. | 34 will work offline. |
35 Your offline-enabled app should follow these rules: | 35 Your offline-enabled app should follow these rules: |
36 </p> | 36 </p> |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
85 It <b>cannot</b> be inline. | 85 It <b>cannot</b> be inline. |
86 <br /> | 86 <br /> |
87 </li> | 87 </li> |
88 <li> All <b>CSS styles</b>, <b>images</b>, and <b>fonts</b> | 88 <li> All <b>CSS styles</b>, <b>images</b>, and <b>fonts</b> |
89 can be initially located | 89 can be initially located |
90 either in the app's package | 90 either in the app's package |
91 or at a remote URL. | 91 or at a remote URL. |
92 If the resource is remote, | 92 If the resource is remote, |
93 you can't specify it in your HTML. | 93 you can't specify it in your HTML. |
94 Instead, get the data using <code>XMLHttpRequest</code> | 94 Instead, get the data using <code>XMLHttpRequest</code> |
95 (see <a href="app_external.html#external">Referencing external resources</a>
). | 95 (see <a href="app_external#external">Referencing external resources</a>). |
96 Then either refer to the data with a blob URL | 96 Then either refer to the data with a blob URL |
97 or (better yet) save and then load the data using the | 97 or (better yet) save and then load the data using the |
98 <a href="app_storage.html">Filesystem API</a>. | 98 <a href="app_storage">Filesystem API</a>. |
99 | 99 |
100 <p class="note"> | 100 <p class="note"> |
101 <b>Note:</b> | 101 <b>Note:</b> |
102 Styles can be inline or in separate <code>.css</code> files. | 102 Styles can be inline or in separate <code>.css</code> files. |
103 </p> | 103 </p> |
104 | 104 |
105 </li> | 105 </li> |
106 </ul> | 106 </ul> |
107 | 107 |
108 <p> | 108 <p> |
109 You can, however, | 109 You can, however, |
110 load large media resources such as videos and sounds | 110 load large media resources such as videos and sounds |
111 from external sites. | 111 from external sites. |
112 One reason for this exception to the rule | 112 One reason for this exception to the rule |
113 is that the <video> and <audio> elements | 113 is that the <video> and <audio> elements |
114 have good fallback behavior when an app | 114 have good fallback behavior when an app |
115 has limited or no connectivity. | 115 has limited or no connectivity. |
116 Another reason is that fetching and serving media | 116 Another reason is that fetching and serving media |
117 with <code>XMLHttpRequest</code> and blob URLs | 117 with <code>XMLHttpRequest</code> and blob URLs |
118 currently does not allow | 118 currently does not allow |
119 streaming or partial buffering. | 119 streaming or partial buffering. |
120 </p> | 120 </p> |
121 | 121 |
122 <p> | 122 <p> |
123 To provide a sandboxed iframe, | 123 To provide a sandboxed iframe, |
124 you can create an <webview> tag. | 124 you can create an <webview> tag. |
125 Its contents can be remote, | 125 Its contents can be remote, |
126 but it has no direct access to the Chrome app APIs | 126 but it has no direct access to the Chrome app APIs |
127 (see <a href="app_external.html#webview">Embed external web pages</a>). | 127 (see <a href="app_external#webview">Embed external web pages</a>). |
128 </p> | 128 </p> |
129 | 129 |
130 <p> | 130 <p> |
131 Some of the restrictions on Chrome Apps are enforced by the | 131 Some of the restrictions on Chrome Apps are enforced by the |
132 <a href="contentSecurityPolicy.html">Content Security Policy (CSP)</a> | 132 <a href="contentSecurityPolicy">Content Security Policy (CSP)</a> |
133 which is always the following and cannot be changed for Chrome Apps: | 133 which is always the following and cannot be changed for Chrome Apps: |
134 </p> | 134 </p> |
135 | 135 |
136 <pre> | 136 <pre> |
137 default-src 'self'; | 137 default-src 'self'; |
138 connect-src *; | 138 connect-src *; |
139 style-src 'self' blob: data: filesystem: 'unsafe-inline'; | 139 style-src 'self' blob: data: filesystem: 'unsafe-inline'; |
140 img-src 'self' blob: data: filesystem:; | 140 img-src 'self' blob: data: filesystem:; |
141 frame-src 'self' blob: data: filesystem:; | 141 frame-src 'self' blob: data: filesystem:; |
142 font-src 'self' blob: data: filesystem:; | 142 font-src 'self' blob: data: filesystem:; |
143 media-src *; | 143 media-src *; |
144 </pre> | 144 </pre> |
145 | 145 |
146 <h2 id="manifest"> Specifying offline_enabled </h2> | 146 <h2 id="manifest"> Specifying offline_enabled </h2> |
147 | 147 |
148 <p> | 148 <p> |
149 It is assumed that your app behaves well offline. If it doesn't, you should | 149 It is assumed that your app behaves well offline. If it doesn't, you should |
150 advertise that fact, so that its launch icon is dimmed when the user is offline. | 150 advertise that fact, so that its launch icon is dimmed when the user is offline. |
151 To do so, set <code>offline_enabled</code> to <code>false</code> in the | 151 To do so, set <code>offline_enabled</code> to <code>false</code> in the |
152 <a href="manifest.html">app manifest file</a>: | 152 <a href="manifest">app manifest file</a>: |
153 </p> | 153 </p> |
154 | 154 |
155 <pre data-filename="manifest.json"> | 155 <pre data-filename="manifest.json"> |
156 { | 156 { |
157 "name": "My app", | 157 "name": "My app", |
158 ... | 158 ... |
159 <b>"offline_enabled": false,</b> | 159 <b>"offline_enabled": false,</b> |
160 ... | 160 ... |
161 } | 161 } |
162 </pre> | 162 </pre> |
163 | 163 |
164 <h2 id="saving-locally"> Saving data locally </h2> | 164 <h2 id="saving-locally"> Saving data locally </h2> |
165 | 165 |
166 <p> | 166 <p> |
167 The following table shows your options for saving data locally | 167 The following table shows your options for saving data locally |
168 (see also <a href="app_storage.html">Manage Data</a>). | 168 (see also <a href="app_storage">Manage Data</a>). |
169 </p> | 169 </p> |
170 | 170 |
171 <table class="simple"> | 171 <table class="simple"> |
172 <tr> | 172 <tr> |
173 <th> API </th> <th> Best use </th> <th> Notes </th> | 173 <th> API </th> <th> Best use </th> <th> Notes </th> |
174 </tr> | 174 </tr> |
175 <tr> | 175 <tr> |
176 <td> Chrome Storage API </td> | 176 <td> Chrome Storage API </td> |
177 <td> Small amounts of string data </td> | 177 <td> Small amounts of string data </td> |
178 <td> Great for settings and state. | 178 <td> Great for settings and state. |
179 Easy to sync remotely (but you don't have to). | 179 Easy to sync remotely (but you don't have to). |
180 Not good for larger amounts of data, | 180 Not good for larger amounts of data, |
181 due to quotas. | 181 due to quotas. |
182 </td> | 182 </td> |
183 </tr> | 183 </tr> |
184 <tr> | 184 <tr> |
185 <td> IndexedDB API </td> | 185 <td> IndexedDB API </td> |
186 <td> Structured data </td> | 186 <td> Structured data </td> |
187 <td> Enables fast searches on data. | 187 <td> Enables fast searches on data. |
188 Use with the | 188 Use with the |
189 <a href="declare_permissions.html">unlimitedStorage permission</a>. </td> | 189 <a href="declare_permissions">unlimitedStorage permission</a>. </td> |
190 </tr> | 190 </tr> |
191 <tr> | 191 <tr> |
192 <td> Filesystem API </td> | 192 <td> Filesystem API </td> |
193 <td> Anything else </td> | 193 <td> Anything else </td> |
194 <td> Provides a sandboxed area where you can store files. | 194 <td> Provides a sandboxed area where you can store files. |
195 Use with the | 195 Use with the |
196 <a href="declare_permissions.html">unlimitedStorage permission</a>. </td> | 196 <a href="declare_permissions">unlimitedStorage permission</a>. </td> |
197 </tr> | 197 </tr> |
198 </table> | 198 </table> |
199 | 199 |
200 <p class="note"> | 200 <p class="note"> |
201 <b>Note:</b> | 201 <b>Note:</b> |
202 Packaged apps cannot use Web SQL Database or localStorage. | 202 Packaged apps cannot use Web SQL Database or localStorage. |
203 The WebSQL specification has been deprecated for awhile now, | 203 The WebSQL specification has been deprecated for awhile now, |
204 and localStorage handles data synchronously | 204 and localStorage handles data synchronously |
205 (which means it can be slow). | 205 (which means it can be slow). |
206 The Storage API handles data asynchronously. | 206 The Storage API handles data asynchronously. |
207 </p> | 207 </p> |
208 | 208 |
209 | 209 |
210 <h2 id="saving-remotely"> Saving data remotely </h2> | 210 <h2 id="saving-remotely"> Saving data remotely </h2> |
211 | 211 |
212 <p> | 212 <p> |
213 In general, how you save data remotely is up to you, | 213 In general, how you save data remotely is up to you, |
214 but some frameworks and APIs can help | 214 but some frameworks and APIs can help |
215 (see <a href="app_frameworks.html">MVC Architecture</a>). | 215 (see <a href="app_frameworks">MVC Architecture</a>). |
216 If you use the Chrome Storage API, | 216 If you use the Chrome Storage API, |
217 then all syncable data | 217 then all syncable data |
218 is automatically synced | 218 is automatically synced |
219 whenever the app is online | 219 whenever the app is online |
220 and the user is signed in to Chrome. | 220 and the user is signed in to Chrome. |
221 If the user isn't signed in, | 221 If the user isn't signed in, |
222 they'll be prompted to sign in. | 222 they'll be prompted to sign in. |
223 However, note that the user's synced data | 223 However, note that the user's synced data |
224 is deleted if the user uninstalls your app. | 224 is deleted if the user uninstalls your app. |
225 <span class="comment"> | 225 <span class="comment"> |
226 {QUESTION: true?} | 226 {QUESTION: true?} |
227 </span> | 227 </span> |
228 </p> | 228 </p> |
229 | 229 |
230 <p> | 230 <p> |
231 Consider saving users' data for at least | 231 Consider saving users' data for at least |
232 30 days after your app is uninstalled, | 232 30 days after your app is uninstalled, |
233 so that users will have a good experience | 233 so that users will have a good experience |
234 if they reinstall your app. | 234 if they reinstall your app. |
235 </p> | 235 </p> |
236 | 236 |
237 | 237 |
238 <h2 id="mvc"> Separating UI from data </h2> | 238 <h2 id="mvc"> Separating UI from data </h2> |
239 | 239 |
240 <p> | 240 <p> |
241 Using an MVC framework can help you design and implement your app | 241 Using an MVC framework can help you design and implement your app |
242 so that the data is completely separate from the app's | 242 so that the data is completely separate from the app's |
243 view on the data. | 243 view on the data. |
244 See <a href="app_frameworks.html">MVC Architecture</a> | 244 See <a href="app_frameworks">MVC Architecture</a> |
245 for a list of MVC frameworks. | 245 for a list of MVC frameworks. |
246 </p> | 246 </p> |
247 | 247 |
248 <p> | 248 <p> |
249 If your app talks to a custom server, | 249 If your app talks to a custom server, |
250 the server should give you data, | 250 the server should give you data, |
251 not chunks of HTML. | 251 not chunks of HTML. |
252 Think in terms of RESTful APIs. | 252 Think in terms of RESTful APIs. |
253 </p> | 253 </p> |
254 | 254 |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
294 switching often between online and offline. | 294 switching often between online and offline. |
295 </li> | 295 </li> |
296 </ul> | 296 </ul> |
297 | 297 |
298 <p> | 298 <p> |
299 Also make sure that the app saves <b>no sensitive user data</b> | 299 Also make sure that the app saves <b>no sensitive user data</b> |
300 (such as passwords) on the user's machine. | 300 (such as passwords) on the user's machine. |
301 </p> | 301 </p> |
302 | 302 |
303 <p class="backtotop"><a href="#top">Back to top</a></p> | 303 <p class="backtotop"><a href="#top">Back to top</a></p> |
OLD | NEW |