cordova-plugin-hot-updates 2.1.1 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +361 -192
- package/package.json +5 -6
- package/plugin.xml +9 -10
- package/src/ios/HotUpdates+Helpers.h +23 -0
- package/src/ios/HotUpdates+Helpers.m +24 -0
- package/src/ios/HotUpdates.h +4 -3
- package/src/ios/HotUpdates.m +45 -211
- package/src/ios/HotUpdatesConstants.h +45 -0
- package/src/ios/HotUpdatesConstants.m +46 -0
- package/www/HotUpdates.js +162 -142
- package/CHANGELOG.md +0 -239
- package/docs/API.md +0 -352
- package/docs/README.md +0 -187
- package/docs/hot-updates-admin.html +0 -467
package/README.md
CHANGED
|
@@ -1,31 +1,23 @@
|
|
|
1
|
-
# Cordova Hot Updates Plugin
|
|
1
|
+
# Cordova Hot Updates Plugin v2.2.0
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Frontend-controlled manual hot updates for Cordova iOS applications using WebView Reload approach.
|
|
4
4
|
|
|
5
5
|
[](https://badge.fury.io/js/cordova-plugin-hot-updates)
|
|
6
6
|
[](#license)
|
|
7
7
|
|
|
8
8
|
This plugin enables **manual, JavaScript-controlled** web content updates for your Cordova iOS applications without requiring App Store approval. Your frontend code decides when to check, download, and install updates.
|
|
9
9
|
|
|
10
|
-
##
|
|
10
|
+
## Features
|
|
11
11
|
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
12
|
+
- **Frontend Control**: JavaScript decides when to update (no automatic background checking)
|
|
13
|
+
- **Two-Step Updates**: Separate download (`getUpdate`) and install (`forceUpdate`) for better UX
|
|
14
|
+
- **Auto-Install on Launch**: If user ignores update prompt, it installs on next app launch
|
|
15
|
+
- **Canary System**: Automatic rollback if update fails to load (20-second timeout)
|
|
16
|
+
- **IgnoreList**: Tracks problematic versions (information only, does NOT block installation)
|
|
17
|
+
- **Instant Effect**: WebView Reload approach - no app restart needed
|
|
18
|
+
- **Cache Management**: Clears WKWebView cache (disk, memory, Service Worker) before reload
|
|
16
19
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
## 🎯 Key Features
|
|
20
|
-
|
|
21
|
-
- **🎮 Frontend Control**: Your JavaScript decides when to update (no automatic background checks)
|
|
22
|
-
- **⚡ Two-Step Updates**: Separate download and install for better UX
|
|
23
|
-
- **🔄 Auto-Install**: If user ignores popup, update installs on next app launch
|
|
24
|
-
- **🐦 Canary System**: Automatic rollback if update fails to load (20-second timeout)
|
|
25
|
-
- **📋 IgnoreList**: Tracks problematic versions (informational only)
|
|
26
|
-
- **🚀 Instant Effect**: WebView Reload approach - no app restart needed
|
|
27
|
-
|
|
28
|
-
## 📦 Installation
|
|
20
|
+
## Installation
|
|
29
21
|
|
|
30
22
|
```bash
|
|
31
23
|
# Install from npm
|
|
@@ -36,166 +28,358 @@ cd platforms/ios
|
|
|
36
28
|
pod install
|
|
37
29
|
```
|
|
38
30
|
|
|
31
|
+
Or install from local directory:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
cordova plugin add /path/to/cordova-plugin-hot-updates
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Or install from GitHub:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
cordova plugin add https://github.com/vladimirDarksy/Cordova_hot_update.git
|
|
41
|
+
```
|
|
42
|
+
|
|
39
43
|
**Requirements:**
|
|
40
44
|
- Cordova >= 7.0.0
|
|
41
45
|
- cordova-ios >= 4.4.0
|
|
42
|
-
- iOS >= 11.
|
|
46
|
+
- iOS >= 11.2
|
|
43
47
|
- CocoaPods (for SSZipArchive dependency)
|
|
44
48
|
|
|
45
|
-
##
|
|
49
|
+
## Quick Start
|
|
46
50
|
|
|
47
51
|
### 1. Minimal Integration
|
|
48
52
|
|
|
49
53
|
```javascript
|
|
50
54
|
document.addEventListener('deviceready', function() {
|
|
51
|
-
//
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
url: data.downloadURL,
|
|
69
|
-
version: data.newVersion
|
|
70
|
-
}, function(error) {
|
|
71
|
-
if (error) {
|
|
72
|
-
console.error('Download failed:', error.error.message);
|
|
73
|
-
return;
|
|
74
|
-
}
|
|
55
|
+
// CRITICAL: Confirm successful bundle load within 20 seconds
|
|
56
|
+
var currentVersion = localStorage.getItem('app_version') || '1.0.0';
|
|
57
|
+
window.hotUpdate.canary(currentVersion);
|
|
58
|
+
|
|
59
|
+
// Check for updates
|
|
60
|
+
checkForUpdates();
|
|
61
|
+
}, false);
|
|
62
|
+
|
|
63
|
+
function checkForUpdates() {
|
|
64
|
+
fetch('https://your-server.com/api/check-update?version=1.0.0')
|
|
65
|
+
.then(response => response.json())
|
|
66
|
+
.then(data => {
|
|
67
|
+
if (data.hasUpdate) {
|
|
68
|
+
downloadAndInstall(data.downloadUrl, data.version);
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
}
|
|
75
72
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
// WebView reloads automatically
|
|
84
|
-
});
|
|
85
|
-
}
|
|
86
|
-
// If user cancels: update installs automatically on next launch
|
|
87
|
-
});
|
|
88
|
-
}
|
|
73
|
+
function downloadAndInstall(url, version) {
|
|
74
|
+
window.hotUpdate.getUpdate({url: url, version: version}, function(error) {
|
|
75
|
+
if (!error) {
|
|
76
|
+
if (confirm('Update available. Install now?')) {
|
|
77
|
+
localStorage.setItem('app_version', version);
|
|
78
|
+
window.hotUpdate.forceUpdate(function(error) {
|
|
79
|
+
// WebView will reload, canary() will be called in deviceready
|
|
89
80
|
});
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
81
|
+
}
|
|
82
|
+
// If user declines, update auto-installs on next launch
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Error Handling
|
|
89
|
+
|
|
90
|
+
All errors are returned in a unified format for programmatic handling:
|
|
91
|
+
|
|
92
|
+
```javascript
|
|
93
|
+
// Error format
|
|
94
|
+
callback({
|
|
95
|
+
error: {
|
|
96
|
+
code: "ERROR_CODE", // Code for programmatic handling
|
|
97
|
+
message: "Detailed message" // Detailed message for logs
|
|
98
|
+
}
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
// Success result
|
|
102
|
+
callback(null)
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Error Codes
|
|
106
|
+
|
|
107
|
+
#### getUpdate() errors:
|
|
108
|
+
- `UPDATE_DATA_REQUIRED` - Missing updateData parameter
|
|
109
|
+
- `URL_REQUIRED` - Missing url parameter
|
|
110
|
+
- `DOWNLOAD_IN_PROGRESS` - Download already in progress
|
|
111
|
+
- `DOWNLOAD_FAILED` - Network download error (message contains details)
|
|
112
|
+
- `HTTP_ERROR` - HTTP status != 200 (message contains status code)
|
|
113
|
+
- `TEMP_DIR_ERROR` - Error creating temporary directory
|
|
114
|
+
- `EXTRACTION_FAILED` - Error extracting ZIP archive
|
|
115
|
+
- `WWW_NOT_FOUND` - www folder not found in archive
|
|
116
|
+
|
|
117
|
+
#### forceUpdate() errors:
|
|
118
|
+
- `NO_UPDATE_READY` - getUpdate() not called first
|
|
119
|
+
- `UPDATE_FILES_NOT_FOUND` - Downloaded update files not found
|
|
120
|
+
- `INSTALL_FAILED` - Error copying files (message contains details)
|
|
121
|
+
|
|
122
|
+
#### canary() errors:
|
|
123
|
+
- `VERSION_REQUIRED` - Missing version parameter
|
|
124
|
+
|
|
125
|
+
### Error Handling Example
|
|
126
|
+
|
|
127
|
+
```javascript
|
|
128
|
+
window.hotUpdate.getUpdate({url: 'http://...'}, function(error) {
|
|
129
|
+
if (error) {
|
|
130
|
+
console.error('[HotUpdates]', error.code, ':', error.message);
|
|
131
|
+
|
|
132
|
+
switch(error.code) {
|
|
133
|
+
case 'HTTP_ERROR':
|
|
134
|
+
// Handle HTTP errors
|
|
135
|
+
break;
|
|
136
|
+
case 'DOWNLOAD_FAILED':
|
|
137
|
+
// Handle network errors
|
|
138
|
+
break;
|
|
139
|
+
default:
|
|
140
|
+
console.error('Unknown error:', error);
|
|
141
|
+
}
|
|
142
|
+
} else {
|
|
143
|
+
console.log('Update downloaded successfully');
|
|
144
|
+
}
|
|
98
145
|
});
|
|
99
146
|
```
|
|
100
147
|
|
|
101
|
-
##
|
|
148
|
+
## API Reference
|
|
149
|
+
|
|
150
|
+
All API methods are available via `window.hotUpdate` after the `deviceready` event.
|
|
151
|
+
|
|
152
|
+
### window.hotUpdate.getUpdate(options, callback)
|
|
102
153
|
|
|
103
|
-
|
|
154
|
+
Downloads update from server.
|
|
104
155
|
|
|
105
|
-
|
|
156
|
+
Downloads ZIP from provided URL and saves to two locations:
|
|
157
|
+
- `temp_downloaded_update` (for immediate installation via `forceUpdate()`)
|
|
158
|
+
- `pending_update` (for auto-installation on next app launch)
|
|
106
159
|
|
|
107
|
-
|
|
160
|
+
If version already downloaded, returns success without re-downloading.
|
|
108
161
|
|
|
162
|
+
**Does NOT check ignoreList** - JavaScript controls all installation decisions.
|
|
163
|
+
|
|
164
|
+
**Parameters:**
|
|
165
|
+
- `options` (Object):
|
|
166
|
+
- `url` (string, required) - URL to download ZIP archive
|
|
167
|
+
- `version` (string, optional) - Version string
|
|
168
|
+
- `callback` (Function) - `callback(error)`
|
|
169
|
+
- `null` on success
|
|
170
|
+
- `{error: {message?: string}}` on error
|
|
171
|
+
|
|
172
|
+
**Example:**
|
|
109
173
|
```javascript
|
|
110
|
-
window.
|
|
111
|
-
url: 'https://server.com/updates/2.
|
|
112
|
-
version: '2.
|
|
174
|
+
window.hotUpdate.getUpdate({
|
|
175
|
+
url: 'https://your-server.com/updates/2.0.0.zip',
|
|
176
|
+
version: '2.0.0'
|
|
113
177
|
}, function(error) {
|
|
114
178
|
if (error) {
|
|
115
|
-
console.error('Download failed:', error
|
|
179
|
+
console.error('Download failed:', error);
|
|
116
180
|
} else {
|
|
117
|
-
console.log('
|
|
181
|
+
console.log('Update downloaded successfully');
|
|
118
182
|
}
|
|
119
183
|
});
|
|
120
184
|
```
|
|
121
185
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
### window.hotUpdate.forceUpdate(callback)
|
|
189
|
+
|
|
190
|
+
Installs downloaded update immediately and reloads WebView.
|
|
191
|
+
|
|
192
|
+
**Process:**
|
|
193
|
+
1. Backup current version to `www_previous`
|
|
194
|
+
2. Copy downloaded update to `Documents/www`
|
|
195
|
+
3. Clear WebView cache (disk, memory, Service Worker)
|
|
196
|
+
4. Reload WebView
|
|
197
|
+
5. Start 20-second canary timer
|
|
198
|
+
|
|
199
|
+
**IMPORTANT:** JavaScript MUST call `canary(version)` within 20 seconds after reload to confirm successful bundle load. Otherwise automatic rollback occurs.
|
|
126
200
|
|
|
127
|
-
|
|
201
|
+
**Does NOT check ignoreList** - JavaScript decides what to install.
|
|
128
202
|
|
|
129
|
-
|
|
203
|
+
**Parameters:**
|
|
204
|
+
- `callback` (Function) - `callback(error)`
|
|
205
|
+
- `null` on success (before WebView reload)
|
|
206
|
+
- `{error: {message?: string}}` on error
|
|
130
207
|
|
|
208
|
+
**Example:**
|
|
131
209
|
```javascript
|
|
132
|
-
window.
|
|
210
|
+
window.hotUpdate.forceUpdate(function(error) {
|
|
133
211
|
if (error) {
|
|
134
|
-
console.error('Install failed:', error
|
|
212
|
+
console.error('Install failed:', error);
|
|
135
213
|
} else {
|
|
136
|
-
console.log('
|
|
214
|
+
console.log('Update installing, WebView will reload...');
|
|
137
215
|
}
|
|
138
216
|
});
|
|
139
217
|
```
|
|
140
218
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
### window.hotUpdate.canary(version, callback)
|
|
222
|
+
|
|
223
|
+
Confirms successful bundle load after update.
|
|
145
224
|
|
|
146
|
-
|
|
225
|
+
**MUST be called within 20 seconds** after `forceUpdate()` to stop canary timer and prevent automatic rollback.
|
|
147
226
|
|
|
148
|
-
|
|
227
|
+
**If not called within 20 seconds:**
|
|
228
|
+
- Automatic rollback to previous version
|
|
229
|
+
- Failed version added to ignoreList
|
|
230
|
+
- WebView reloaded with previous version
|
|
149
231
|
|
|
232
|
+
**Parameters:**
|
|
233
|
+
- `version` (string) - Version that loaded successfully
|
|
234
|
+
- `callback` (Function, optional) - Not used, method is synchronous
|
|
235
|
+
|
|
236
|
+
**Example:**
|
|
150
237
|
```javascript
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
238
|
+
document.addEventListener('deviceready', function() {
|
|
239
|
+
var version = localStorage.getItem('app_version') || '1.0.0';
|
|
240
|
+
window.hotUpdate.canary(version);
|
|
241
|
+
}, false);
|
|
154
242
|
```
|
|
155
243
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
244
|
+
---
|
|
245
|
+
|
|
246
|
+
### window.hotUpdate.getIgnoreList(callback)
|
|
247
|
+
|
|
248
|
+
Returns list of problematic versions (information only).
|
|
249
|
+
|
|
250
|
+
**This is an INFORMATION-ONLY system** - native does NOT block installation. JavaScript should read this list and decide whether to skip these versions.
|
|
160
251
|
|
|
161
|
-
|
|
252
|
+
Native automatically adds versions to this list when rollback occurs.
|
|
162
253
|
|
|
163
|
-
|
|
254
|
+
**Parameters:**
|
|
255
|
+
- `callback` (Function) - `callback(result)`
|
|
256
|
+
- `result`: `{versions: string[]}` - Array of problematic version strings
|
|
164
257
|
|
|
258
|
+
**Example:**
|
|
165
259
|
```javascript
|
|
166
|
-
window.
|
|
167
|
-
|
|
260
|
+
window.hotUpdate.getIgnoreList(function(result) {
|
|
261
|
+
console.log('Problematic versions:', result.versions);
|
|
168
262
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
// Safe to download
|
|
263
|
+
if (result.versions.includes(newVersion)) {
|
|
264
|
+
console.log('Skipping known problematic version');
|
|
172
265
|
}
|
|
173
266
|
});
|
|
174
267
|
```
|
|
175
268
|
|
|
176
|
-
|
|
269
|
+
---
|
|
177
270
|
|
|
178
|
-
##
|
|
271
|
+
## Complete Update Flow
|
|
179
272
|
|
|
180
|
-
|
|
273
|
+
```javascript
|
|
274
|
+
// Step 1: Check for updates on your server
|
|
275
|
+
function checkForUpdates() {
|
|
276
|
+
var currentVersion = localStorage.getItem('app_version') || '1.0.0';
|
|
277
|
+
|
|
278
|
+
fetch('https://your-server.com/api/check-update?version=' + currentVersion)
|
|
279
|
+
.then(response => response.json())
|
|
280
|
+
.then(data => {
|
|
281
|
+
if (data.hasUpdate) {
|
|
282
|
+
// Step 2: Check ignoreList
|
|
283
|
+
window.hotUpdate.getIgnoreList(function(ignoreList) {
|
|
284
|
+
if (ignoreList.versions.includes(data.version)) {
|
|
285
|
+
console.log('Skipping problematic version');
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// Step 3: Download
|
|
290
|
+
window.hotUpdate.getUpdate({
|
|
291
|
+
url: data.downloadUrl,
|
|
292
|
+
version: data.version
|
|
293
|
+
}, function(error) {
|
|
294
|
+
if (!error) {
|
|
295
|
+
// Step 4: Prompt user
|
|
296
|
+
if (confirm('Update available. Install now?')) {
|
|
297
|
+
// Save version for canary check
|
|
298
|
+
localStorage.setItem('app_version', data.version);
|
|
299
|
+
|
|
300
|
+
// Step 5: Install
|
|
301
|
+
window.hotUpdate.forceUpdate(function(error) {
|
|
302
|
+
// WebView will reload
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
// If declined, auto-installs on next launch
|
|
306
|
+
}
|
|
307
|
+
});
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// Step 6: After reload, confirm success
|
|
314
|
+
document.addEventListener('deviceready', function() {
|
|
315
|
+
var version = localStorage.getItem('app_version') || '1.0.0';
|
|
316
|
+
window.hotUpdate.canary(version); // Must call within 20 seconds!
|
|
317
|
+
|
|
318
|
+
initApp();
|
|
319
|
+
}, false);
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
## How It Works
|
|
323
|
+
|
|
324
|
+
### Update Flow
|
|
181
325
|
|
|
182
|
-
|
|
326
|
+
1. **Download** (`getUpdate()`):
|
|
327
|
+
- Downloads ZIP from URL
|
|
328
|
+
- Validates `www` folder structure
|
|
329
|
+
- Saves to TWO locations:
|
|
330
|
+
- `temp_downloaded_update` (for immediate install)
|
|
331
|
+
- `pending_update` (for auto-install on next launch)
|
|
183
332
|
|
|
184
|
-
**
|
|
333
|
+
2. **Installation Options**:
|
|
334
|
+
- **Immediate**: User clicks "Update" → `forceUpdate()` installs now
|
|
335
|
+
- **Deferred**: User ignores → Auto-installs on next app launch
|
|
336
|
+
|
|
337
|
+
3. **Rollback Protection**:
|
|
338
|
+
- Previous version backed up before installation
|
|
339
|
+
- 20-second canary timer starts after reload
|
|
340
|
+
- If `canary()` not called → automatic rollback
|
|
341
|
+
- Failed version added to ignoreList
|
|
342
|
+
|
|
343
|
+
4. **IgnoreList System**:
|
|
344
|
+
- Native tracks failed versions
|
|
345
|
+
- JavaScript reads via `getIgnoreList()`
|
|
346
|
+
- **Does NOT block** - JS decides what to install
|
|
347
|
+
|
|
348
|
+
### Storage Structure
|
|
349
|
+
|
|
350
|
+
```
|
|
351
|
+
Documents/
|
|
352
|
+
├── www/ // Active version
|
|
353
|
+
├── www_previous/ // Previous version (rollback)
|
|
354
|
+
├── pending_update/ // Next launch auto-install
|
|
355
|
+
└── temp_downloaded_update/ // Immediate install
|
|
356
|
+
```
|
|
185
357
|
|
|
186
|
-
|
|
358
|
+
### Version Management
|
|
359
|
+
|
|
360
|
+
- **appBundleVersion** - Native app version from Info.plist
|
|
361
|
+
- **installedVersion** - Current hot update version
|
|
362
|
+
- **previousVersion** - Last working version (rollback)
|
|
363
|
+
|
|
364
|
+
## Update Server API
|
|
365
|
+
|
|
366
|
+
Your server should provide:
|
|
367
|
+
|
|
368
|
+
**Check API:**
|
|
369
|
+
```
|
|
370
|
+
GET https://your-server.com/api/check-update?version=1.0.0&platform=ios
|
|
371
|
+
|
|
372
|
+
Response:
|
|
187
373
|
{
|
|
188
374
|
"hasUpdate": true,
|
|
189
|
-
"
|
|
190
|
-
"
|
|
191
|
-
"minAppVersion": "2.7.0"
|
|
375
|
+
"version": "2.0.0",
|
|
376
|
+
"downloadUrl": "https://your-server.com/updates/2.0.0.zip",
|
|
377
|
+
"minAppVersion": "2.7.0",
|
|
378
|
+
"releaseNotes": "Bug fixes"
|
|
192
379
|
}
|
|
193
380
|
```
|
|
194
381
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
ZIP file containing `www` folder:
|
|
198
|
-
|
|
382
|
+
**Update ZIP Structure:**
|
|
199
383
|
```
|
|
200
384
|
update.zip
|
|
201
385
|
└── www/
|
|
@@ -205,105 +389,90 @@ update.zip
|
|
|
205
389
|
└── ...
|
|
206
390
|
```
|
|
207
391
|
|
|
208
|
-
##
|
|
392
|
+
## Best Practices
|
|
209
393
|
|
|
210
|
-
###
|
|
394
|
+
### 1. Always Call Canary
|
|
211
395
|
|
|
396
|
+
```javascript
|
|
397
|
+
document.addEventListener('deviceready', function() {
|
|
398
|
+
var version = localStorage.getItem('app_version');
|
|
399
|
+
window.hotUpdate.canary(version); // Within 20 seconds!
|
|
400
|
+
}, false);
|
|
212
401
|
```
|
|
213
|
-
1. JS checks YOUR server for updates
|
|
214
|
-
2. getUpdate() downloads ZIP in background
|
|
215
|
-
3. Show popup to user
|
|
216
|
-
4. User clicks "Update": forceUpdate() installs immediately
|
|
217
|
-
5. User ignores: update auto-installs on next app launch
|
|
218
|
-
6. WebView reloads with new content
|
|
219
|
-
7. JS calls canary() to confirm success
|
|
220
|
-
```
|
|
221
|
-
|
|
222
|
-
### Rollback Protection
|
|
223
|
-
|
|
224
|
-
- 20-second canary timer starts after update
|
|
225
|
-
- If `canary()` not called → automatic rollback
|
|
226
|
-
- Failed version added to ignore list
|
|
227
|
-
- App continues working on previous version
|
|
228
402
|
|
|
229
|
-
###
|
|
403
|
+
### 2. Check IgnoreList
|
|
230
404
|
|
|
405
|
+
```javascript
|
|
406
|
+
window.hotUpdate.getIgnoreList(function(result) {
|
|
407
|
+
if (result.versions.includes(newVersion)) {
|
|
408
|
+
console.log('Known problematic version');
|
|
409
|
+
}
|
|
410
|
+
});
|
|
231
411
|
```
|
|
232
|
-
Documents/
|
|
233
|
-
├── www/ # Active version
|
|
234
|
-
├── www_previous/ # Backup (for rollback)
|
|
235
|
-
├── pending_update/ # Next launch auto-install
|
|
236
|
-
└── temp_downloaded_update/ # Immediate install
|
|
237
|
-
```
|
|
238
|
-
|
|
239
|
-
## 📖 Full Documentation
|
|
240
|
-
|
|
241
|
-
- **[docs/README.md](docs/README.md)** - Quick start guide
|
|
242
|
-
- **[docs/API.md](docs/API.md)** - Complete API reference
|
|
243
|
-
- **[docs/hot-updates-admin.html](docs/hot-updates-admin.html)** - Testing interface
|
|
244
|
-
- **[CHANGELOG.md](CHANGELOG.md)** - Version history
|
|
245
412
|
|
|
246
|
-
|
|
413
|
+
### 3. Handle Errors
|
|
247
414
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
415
|
+
```javascript
|
|
416
|
+
window.hotUpdate.getUpdate(options, function(error) {
|
|
417
|
+
if (error) {
|
|
418
|
+
analytics.track('update_failed', {error: error.message});
|
|
419
|
+
showUserMessage('Update failed');
|
|
420
|
+
}
|
|
421
|
+
});
|
|
422
|
+
```
|
|
254
423
|
|
|
255
|
-
|
|
256
|
-
- ✅ Fixed in v2.1.0! `getUpdate()` now checks installed version
|
|
424
|
+
### 4. Store Version
|
|
257
425
|
|
|
258
|
-
|
|
259
|
-
|
|
426
|
+
```javascript
|
|
427
|
+
// Before forceUpdate
|
|
428
|
+
localStorage.setItem('app_version', newVersion);
|
|
260
429
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
pod install
|
|
265
|
-
cordova clean ios && cordova build ios
|
|
430
|
+
// After reload
|
|
431
|
+
var version = localStorage.getItem('app_version');
|
|
432
|
+
window.hotUpdate.canary(version);
|
|
266
433
|
```
|
|
267
434
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
All plugin actions are logged with `[HotUpdates]` prefix:
|
|
435
|
+
## Troubleshooting
|
|
271
436
|
|
|
272
|
-
|
|
273
|
-
# iOS Simulator
|
|
274
|
-
cordova run ios --debug
|
|
275
|
-
|
|
276
|
-
# iOS Device
|
|
277
|
-
# Use Xcode console or Safari Web Inspector
|
|
278
|
-
```
|
|
437
|
+
### Update doesn't install
|
|
279
438
|
|
|
280
|
-
|
|
439
|
+
- Check ZIP structure (must have `www/` folder)
|
|
440
|
+
- Check URL accessibility
|
|
441
|
+
- Check Xcode console: `[HotUpdates] ...`
|
|
281
442
|
|
|
282
|
-
|
|
283
|
-
- **Manual Updates Only**: No automatic background checking (you control everything)
|
|
284
|
-
- **App Store Compliance**: Only update web content, not native code
|
|
285
|
-
- **HTTPS Required**: Update server should use HTTPS in production
|
|
286
|
-
- **Testing**: Test rollback mechanism thoroughly
|
|
443
|
+
### Automatic rollback
|
|
287
444
|
|
|
288
|
-
|
|
445
|
+
**Cause:** `canary()` not called within 20 seconds
|
|
289
446
|
|
|
290
|
-
|
|
447
|
+
**Solution:** Call immediately in `deviceready`:
|
|
448
|
+
```javascript
|
|
449
|
+
document.addEventListener('deviceready', function() {
|
|
450
|
+
window.hotUpdate.canary(version); // First thing!
|
|
451
|
+
}, false);
|
|
452
|
+
```
|
|
291
453
|
|
|
292
|
-
|
|
454
|
+
### window.hotUpdate is undefined
|
|
293
455
|
|
|
294
|
-
|
|
456
|
+
**Cause:** Called before `deviceready`
|
|
295
457
|
|
|
296
|
-
|
|
458
|
+
**Solution:**
|
|
459
|
+
```javascript
|
|
460
|
+
document.addEventListener('deviceready', function() {
|
|
461
|
+
console.log(window.hotUpdate); // Now available
|
|
462
|
+
}, false);
|
|
463
|
+
```
|
|
297
464
|
|
|
298
|
-
|
|
465
|
+
## License
|
|
299
466
|
|
|
300
|
-
|
|
467
|
+
Custom Non-Commercial License - See [LICENSE](LICENSE) file
|
|
301
468
|
|
|
302
|
-
|
|
303
|
-
- **npm**: [cordova-plugin-hot-updates](https://www.npmjs.com/package/cordova-plugin-hot-updates)
|
|
469
|
+
## Author
|
|
304
470
|
|
|
305
|
-
|
|
471
|
+
**Mustafin Vladimir**
|
|
472
|
+
- GitHub: [@vladimirDarksy](https://github.com/vladimirDarksy)
|
|
473
|
+
- Email: outvova.gor@gmail.com
|
|
306
474
|
|
|
307
|
-
|
|
475
|
+
## Support
|
|
308
476
|
|
|
309
|
-
|
|
477
|
+
- Issues: https://github.com/vladimirDarksy/Cordova_hot_update/issues
|
|
478
|
+
- Repository: https://github.com/vladimirDarksy/Cordova_hot_update
|