cordova-plugin-hot-updates 2.1.2 → 2.2.1
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 +87 -42
- package/package.json +2 -2
- package/plugin.xml +5 -1
- package/src/ios/HotUpdates+Helpers.h +23 -0
- package/src/ios/HotUpdates+Helpers.m +24 -0
- package/src/ios/HotUpdates.h +6 -31
- package/src/ios/HotUpdates.m +128 -250
- package/src/ios/HotUpdatesConstants.h +51 -0
- package/src/ios/HotUpdatesConstants.m +46 -0
- package/www/HotUpdates.js +109 -116
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* @file HotUpdatesConstants.h
|
|
3
|
+
* @brief Constants for Hot Updates Plugin
|
|
4
|
+
* @details Contains error codes, storage keys, and directory names used by the plugin
|
|
5
|
+
* @version 2.1.0
|
|
6
|
+
* @date 2025-11-13
|
|
7
|
+
* @author Mustafin Vladimir
|
|
8
|
+
* @copyright Copyright (c) 2025. All rights reserved.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
#ifndef HotUpdatesConstants_h
|
|
12
|
+
#define HotUpdatesConstants_h
|
|
13
|
+
|
|
14
|
+
#pragma mark - Error Codes
|
|
15
|
+
|
|
16
|
+
// Error codes returned to JavaScript
|
|
17
|
+
extern NSString * const kErrorUpdateDataRequired;
|
|
18
|
+
extern NSString * const kErrorURLRequired;
|
|
19
|
+
extern NSString * const kErrorDownloadInProgress;
|
|
20
|
+
extern NSString * const kErrorDownloadFailed;
|
|
21
|
+
extern NSString * const kErrorHTTPError;
|
|
22
|
+
extern NSString * const kErrorTempDirError;
|
|
23
|
+
extern NSString * const kErrorExtractionFailed;
|
|
24
|
+
extern NSString * const kErrorWWWNotFound;
|
|
25
|
+
extern NSString * const kErrorNoUpdateReady;
|
|
26
|
+
extern NSString * const kErrorUpdateFilesNotFound;
|
|
27
|
+
extern NSString * const kErrorInstallFailed;
|
|
28
|
+
extern NSString * const kErrorVersionRequired;
|
|
29
|
+
|
|
30
|
+
#pragma mark - Storage Keys
|
|
31
|
+
|
|
32
|
+
// NSUserDefaults keys
|
|
33
|
+
extern NSString * const kInstalledVersion;
|
|
34
|
+
extern NSString * const kPendingVersion;
|
|
35
|
+
extern NSString * const kHasPending;
|
|
36
|
+
extern NSString * const kPreviousVersion;
|
|
37
|
+
extern NSString * const kIgnoreList;
|
|
38
|
+
extern NSString * const kCanaryVersion;
|
|
39
|
+
extern NSString * const kDownloadInProgress;
|
|
40
|
+
extern NSString * const kPendingUpdateURL;
|
|
41
|
+
extern NSString * const kPendingUpdateReady;
|
|
42
|
+
|
|
43
|
+
#pragma mark - Directory Names
|
|
44
|
+
|
|
45
|
+
// Directory names
|
|
46
|
+
extern NSString * const kWWWDirName;
|
|
47
|
+
extern NSString * const kPreviousWWWDirName;
|
|
48
|
+
extern NSString * const kBackupWWWDirName;
|
|
49
|
+
extern NSString * const kPendingUpdateDirName;
|
|
50
|
+
|
|
51
|
+
#endif /* HotUpdatesConstants_h */
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* @file HotUpdatesConstants.m
|
|
3
|
+
* @brief Implementation of constants for Hot Updates Plugin
|
|
4
|
+
* @details Defines all constant values used throughout the plugin
|
|
5
|
+
* @version 2.1.0
|
|
6
|
+
* @date 2025-11-13
|
|
7
|
+
* @author Mustafin Vladimir
|
|
8
|
+
* @copyright Copyright (c) 2025. All rights reserved.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
#import <Foundation/Foundation.h>
|
|
12
|
+
#import "HotUpdatesConstants.h"
|
|
13
|
+
|
|
14
|
+
#pragma mark - Error Codes
|
|
15
|
+
|
|
16
|
+
NSString * const kErrorUpdateDataRequired = @"UPDATE_DATA_REQUIRED";
|
|
17
|
+
NSString * const kErrorURLRequired = @"URL_REQUIRED";
|
|
18
|
+
NSString * const kErrorDownloadInProgress = @"DOWNLOAD_IN_PROGRESS";
|
|
19
|
+
NSString * const kErrorDownloadFailed = @"DOWNLOAD_FAILED";
|
|
20
|
+
NSString * const kErrorHTTPError = @"HTTP_ERROR";
|
|
21
|
+
NSString * const kErrorTempDirError = @"TEMP_DIR_ERROR";
|
|
22
|
+
NSString * const kErrorExtractionFailed = @"EXTRACTION_FAILED";
|
|
23
|
+
NSString * const kErrorWWWNotFound = @"WWW_NOT_FOUND";
|
|
24
|
+
NSString * const kErrorNoUpdateReady = @"NO_UPDATE_READY";
|
|
25
|
+
NSString * const kErrorUpdateFilesNotFound = @"UPDATE_FILES_NOT_FOUND";
|
|
26
|
+
NSString * const kErrorInstallFailed = @"INSTALL_FAILED";
|
|
27
|
+
NSString * const kErrorVersionRequired = @"VERSION_REQUIRED";
|
|
28
|
+
|
|
29
|
+
#pragma mark - Storage Keys
|
|
30
|
+
|
|
31
|
+
NSString * const kInstalledVersion = @"hot_updates_installed_version";
|
|
32
|
+
NSString * const kPendingVersion = @"hot_updates_pending_version";
|
|
33
|
+
NSString * const kHasPending = @"hot_updates_has_pending";
|
|
34
|
+
NSString * const kPreviousVersion = @"hot_updates_previous_version";
|
|
35
|
+
NSString * const kIgnoreList = @"hot_updates_ignore_list";
|
|
36
|
+
NSString * const kCanaryVersion = @"hot_updates_canary_version";
|
|
37
|
+
NSString * const kDownloadInProgress = @"hot_updates_download_in_progress";
|
|
38
|
+
NSString * const kPendingUpdateURL = @"hot_updates_pending_update_url";
|
|
39
|
+
NSString * const kPendingUpdateReady = @"hot_updates_pending_ready";
|
|
40
|
+
|
|
41
|
+
#pragma mark - Directory Names
|
|
42
|
+
|
|
43
|
+
NSString * const kWWWDirName = @"www";
|
|
44
|
+
NSString * const kPreviousWWWDirName = @"www_previous";
|
|
45
|
+
NSString * const kBackupWWWDirName = @"www_backup";
|
|
46
|
+
NSString * const kPendingUpdateDirName = @"pending_update";
|
package/www/HotUpdates.js
CHANGED
|
@@ -1,73 +1,80 @@
|
|
|
1
1
|
var exec = require('cordova/exec');
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* Cordova Hot Updates Plugin v2.1
|
|
4
|
+
* Cordova Hot Updates Plugin v2.2.1
|
|
5
5
|
* Frontend-controlled manual hot updates for iOS
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
* using the WebView Reload approach. All update decisions are controlled
|
|
9
|
-
* by JavaScript - the native plugin only executes commands.
|
|
10
|
-
*
|
|
11
|
-
* Features:
|
|
12
|
-
* - Frontend-controlled manual updates (no automatic checking)
|
|
13
|
-
* - Two-step update flow: getUpdate() downloads, forceUpdate() installs
|
|
14
|
-
* - Automatic rollback with 20-second canary timer
|
|
15
|
-
* - IgnoreList system for tracking problematic versions (information only)
|
|
16
|
-
* - Auto-install pending updates on next app launch
|
|
17
|
-
* - WebView reload approach for instant updates without app restart
|
|
18
|
-
* - No App Store approval required for web content updates
|
|
19
|
-
*
|
|
20
|
-
* @version 2.1.2
|
|
7
|
+
* @version 2.2.1
|
|
21
8
|
* @author Mustafin Vladimir
|
|
22
9
|
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Error codes returned by the plugin
|
|
13
|
+
* @readonly
|
|
14
|
+
* @enum {string}
|
|
15
|
+
*/
|
|
16
|
+
var ErrorCodes = {
|
|
17
|
+
// getUpdate errors
|
|
18
|
+
UPDATE_DATA_REQUIRED: 'UPDATE_DATA_REQUIRED',
|
|
19
|
+
URL_REQUIRED: 'URL_REQUIRED',
|
|
20
|
+
DOWNLOAD_IN_PROGRESS: 'DOWNLOAD_IN_PROGRESS',
|
|
21
|
+
DOWNLOAD_FAILED: 'DOWNLOAD_FAILED',
|
|
22
|
+
HTTP_ERROR: 'HTTP_ERROR',
|
|
23
|
+
TEMP_DIR_ERROR: 'TEMP_DIR_ERROR',
|
|
24
|
+
EXTRACTION_FAILED: 'EXTRACTION_FAILED',
|
|
25
|
+
WWW_NOT_FOUND: 'WWW_NOT_FOUND',
|
|
26
|
+
// forceUpdate errors
|
|
27
|
+
NO_UPDATE_READY: 'NO_UPDATE_READY',
|
|
28
|
+
UPDATE_FILES_NOT_FOUND: 'UPDATE_FILES_NOT_FOUND',
|
|
29
|
+
INSTALL_FAILED: 'INSTALL_FAILED',
|
|
30
|
+
// canary errors
|
|
31
|
+
VERSION_REQUIRED: 'VERSION_REQUIRED'
|
|
32
|
+
};
|
|
33
|
+
|
|
23
34
|
var HotUpdates = {
|
|
24
35
|
|
|
36
|
+
/**
|
|
37
|
+
* Error codes enum
|
|
38
|
+
* @type {Object}
|
|
39
|
+
*/
|
|
40
|
+
ErrorCodes: ErrorCodes,
|
|
41
|
+
|
|
25
42
|
/**
|
|
26
43
|
* Download update from server
|
|
27
44
|
*
|
|
28
|
-
* Downloads update ZIP archive from the provided URL and saves to two locations:
|
|
29
|
-
* - temp_downloaded_update (for immediate installation via forceUpdate)
|
|
30
|
-
* - pending_update (for auto-installation on next app launch)
|
|
31
|
-
*
|
|
32
|
-
* If the specified version is already downloaded, returns success without re-downloading.
|
|
33
|
-
* Does NOT check ignoreList - JavaScript controls all installation decisions.
|
|
34
|
-
*
|
|
35
45
|
* @param {Object} options - Update options
|
|
36
46
|
* @param {string} options.url - URL to download ZIP archive (required)
|
|
37
47
|
* @param {string} [options.version] - Version string (optional)
|
|
38
|
-
* @param {Function} callback - Callback
|
|
39
|
-
* -
|
|
40
|
-
* -
|
|
48
|
+
* @param {Function} callback - Callback(error)
|
|
49
|
+
* - null on success
|
|
50
|
+
* - {error: {code: string, message: string}} on error
|
|
41
51
|
*
|
|
42
52
|
* @example
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
* }, function(error) {
|
|
47
|
-
* if (error) {
|
|
48
|
-
* console.error('Download failed:', error);
|
|
49
|
-
* } else {
|
|
50
|
-
* console.log('Update downloaded successfully');
|
|
51
|
-
* // Can now call forceUpdate() to install immediately
|
|
52
|
-
* // Or user can ignore and it will auto-install on next launch
|
|
53
|
-
* }
|
|
53
|
+
* hotUpdate.getUpdate({url: 'https://server.com/update.zip', version: '2.0.0'}, function(err) {
|
|
54
|
+
* if (err) console.error(err.error.code, err.error.message);
|
|
55
|
+
* else console.log('Downloaded');
|
|
54
56
|
* });
|
|
55
57
|
*/
|
|
56
58
|
getUpdate: function(options, callback) {
|
|
57
|
-
if (!options
|
|
59
|
+
if (!options) {
|
|
60
|
+
if (callback) {
|
|
61
|
+
callback({error: {code: ErrorCodes.UPDATE_DATA_REQUIRED, message: 'Update data required'}});
|
|
62
|
+
}
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (!options.url) {
|
|
58
67
|
if (callback) {
|
|
59
|
-
callback({error: {message: 'URL is required'}});
|
|
68
|
+
callback({error: {code: ErrorCodes.URL_REQUIRED, message: 'URL is required'}});
|
|
60
69
|
}
|
|
61
70
|
return;
|
|
62
71
|
}
|
|
63
72
|
|
|
64
73
|
exec(
|
|
65
74
|
function() {
|
|
66
|
-
// Success
|
|
67
75
|
if (callback) callback(null);
|
|
68
76
|
},
|
|
69
77
|
function(error) {
|
|
70
|
-
// Error
|
|
71
78
|
if (callback) callback({error: error});
|
|
72
79
|
},
|
|
73
80
|
'HotUpdates',
|
|
@@ -79,42 +86,22 @@ var HotUpdates = {
|
|
|
79
86
|
/**
|
|
80
87
|
* Install downloaded update immediately
|
|
81
88
|
*
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
* 2. Copy downloaded update to Documents/www
|
|
86
|
-
* 3. Clear WebView cache (disk, memory, Service Worker)
|
|
87
|
-
* 4. Reload WebView
|
|
88
|
-
* 5. Start 20-second canary timer
|
|
89
|
-
*
|
|
90
|
-
* IMPORTANT: JavaScript MUST call canary(version) within 20 seconds
|
|
91
|
-
* after reload to confirm successful bundle load. Otherwise automatic
|
|
92
|
-
* rollback will occur.
|
|
93
|
-
*
|
|
94
|
-
* Does NOT check ignoreList - JavaScript decides what to install.
|
|
95
|
-
*
|
|
96
|
-
* @param {Function} callback - Callback function
|
|
97
|
-
* - Called with null on success (before WebView reload)
|
|
98
|
-
* - Called with {error: {message?: string}} on error
|
|
89
|
+
* @param {Function} callback - Callback(error)
|
|
90
|
+
* - null on success (WebView will reload)
|
|
91
|
+
* - {error: {code: string, message: string}} on error
|
|
99
92
|
*
|
|
100
93
|
* @example
|
|
101
|
-
*
|
|
102
|
-
* if (error)
|
|
103
|
-
*
|
|
104
|
-
* } else {
|
|
105
|
-
* console.log('Update installing, WebView will reload...');
|
|
106
|
-
* // After reload, MUST call canary() within 20 seconds!
|
|
107
|
-
* }
|
|
94
|
+
* hotUpdate.forceUpdate(function(err) {
|
|
95
|
+
* if (err) console.error(err.error.code);
|
|
96
|
+
* // WebView reloads, call canary() within 20 sec
|
|
108
97
|
* });
|
|
109
98
|
*/
|
|
110
99
|
forceUpdate: function(callback) {
|
|
111
100
|
exec(
|
|
112
101
|
function() {
|
|
113
|
-
// Success
|
|
114
102
|
if (callback) callback(null);
|
|
115
103
|
},
|
|
116
104
|
function(error) {
|
|
117
|
-
// Error
|
|
118
105
|
if (callback) callback({error: error});
|
|
119
106
|
},
|
|
120
107
|
'HotUpdates',
|
|
@@ -124,36 +111,30 @@ var HotUpdates = {
|
|
|
124
111
|
},
|
|
125
112
|
|
|
126
113
|
/**
|
|
127
|
-
* Confirm successful bundle load (
|
|
128
|
-
*
|
|
129
|
-
* MUST be called within 20 seconds after forceUpdate() to confirm
|
|
130
|
-
* that the new bundle loaded successfully. This stops the canary timer
|
|
131
|
-
* and prevents automatic rollback.
|
|
132
|
-
*
|
|
133
|
-
* If not called within 20 seconds:
|
|
134
|
-
* - Automatic rollback to previous version
|
|
135
|
-
* - Failed version added to ignoreList
|
|
136
|
-
* - WebView reloaded with previous version
|
|
137
|
-
*
|
|
138
|
-
* Call this immediately after your app initialization completes.
|
|
114
|
+
* Confirm successful bundle load (MUST call within 20 sec after forceUpdate)
|
|
139
115
|
*
|
|
140
|
-
* @param {string} version -
|
|
141
|
-
* @param {Function} [callback] - Optional callback
|
|
116
|
+
* @param {string} version - Current version
|
|
117
|
+
* @param {Function} [callback] - Optional callback
|
|
142
118
|
*
|
|
143
119
|
* @example
|
|
144
|
-
* // Call as early as possible after app loads
|
|
145
120
|
* document.addEventListener('deviceready', function() {
|
|
146
|
-
*
|
|
147
|
-
*
|
|
148
|
-
* }, false);
|
|
121
|
+
* hotUpdate.canary('2.0.0');
|
|
122
|
+
* });
|
|
149
123
|
*/
|
|
150
124
|
canary: function(version, callback) {
|
|
125
|
+
if (!version) {
|
|
126
|
+
if (callback) {
|
|
127
|
+
callback({error: {code: ErrorCodes.VERSION_REQUIRED, message: 'Version is required'}});
|
|
128
|
+
}
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
|
|
151
132
|
exec(
|
|
152
133
|
function() {
|
|
153
|
-
if (callback) callback();
|
|
134
|
+
if (callback) callback(null);
|
|
154
135
|
},
|
|
155
|
-
function() {
|
|
156
|
-
if (callback) callback();
|
|
136
|
+
function(error) {
|
|
137
|
+
if (callback) callback({error: error});
|
|
157
138
|
},
|
|
158
139
|
'HotUpdates',
|
|
159
140
|
'canary',
|
|
@@ -162,50 +143,62 @@ var HotUpdates = {
|
|
|
162
143
|
},
|
|
163
144
|
|
|
164
145
|
/**
|
|
165
|
-
* Get list of problematic versions
|
|
146
|
+
* Get list of problematic versions
|
|
166
147
|
*
|
|
167
|
-
*
|
|
168
|
-
* This is an INFORMATION-ONLY system - native does NOT block installation
|
|
169
|
-
* of versions in this list.
|
|
170
|
-
*
|
|
171
|
-
* JavaScript should read this list and decide whether to skip downloading/
|
|
172
|
-
* installing these versions. If JS decides to install a version from the
|
|
173
|
-
* ignoreList, that's allowed (per TS requirements).
|
|
174
|
-
*
|
|
175
|
-
* Native automatically adds versions to this list when rollback occurs.
|
|
176
|
-
* JavaScript cannot modify the list (no add/remove/clear methods per TS v2.1.0).
|
|
177
|
-
*
|
|
178
|
-
* @param {Function} callback - Callback function
|
|
179
|
-
* - Called with {versions: string[]} - Array of problematic version strings
|
|
148
|
+
* @param {Function} callback - Callback({versions: string[]})
|
|
180
149
|
*
|
|
181
150
|
* @example
|
|
182
|
-
*
|
|
183
|
-
*
|
|
184
|
-
*
|
|
185
|
-
*
|
|
186
|
-
* // JavaScript decides what to do with this information
|
|
187
|
-
* var shouldSkip = result.versions.includes(availableVersion);
|
|
188
|
-
* if (shouldSkip) {
|
|
189
|
-
* console.log('Skipping known problematic version');
|
|
190
|
-
* } else {
|
|
191
|
-
* // Download and install
|
|
151
|
+
* hotUpdate.getIgnoreList(function(result) {
|
|
152
|
+
* if (result.versions.includes(newVersion)) {
|
|
153
|
+
* console.log('Version is blacklisted');
|
|
192
154
|
* }
|
|
193
155
|
* });
|
|
194
156
|
*/
|
|
195
157
|
getIgnoreList: function(callback) {
|
|
196
158
|
exec(
|
|
197
|
-
function(
|
|
198
|
-
|
|
199
|
-
if (callback) callback({versions: versions || []});
|
|
159
|
+
function(result) {
|
|
160
|
+
if (callback) callback(result || {versions: []});
|
|
200
161
|
},
|
|
201
|
-
function(
|
|
202
|
-
// Error - return empty list
|
|
162
|
+
function() {
|
|
203
163
|
if (callback) callback({versions: []});
|
|
204
164
|
},
|
|
205
165
|
'HotUpdates',
|
|
206
166
|
'getIgnoreList',
|
|
207
167
|
[]
|
|
208
168
|
);
|
|
169
|
+
},
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Get version info (debug method)
|
|
173
|
+
*
|
|
174
|
+
* @param {Function} callback - Callback with version info
|
|
175
|
+
* {
|
|
176
|
+
* appBundleVersion: string,
|
|
177
|
+
* installedVersion: string|null,
|
|
178
|
+
* previousVersion: string|null,
|
|
179
|
+
* canaryVersion: string|null,
|
|
180
|
+
* pendingVersion: string|null,
|
|
181
|
+
* hasPendingUpdate: boolean,
|
|
182
|
+
* ignoreList: string[]
|
|
183
|
+
* }
|
|
184
|
+
*
|
|
185
|
+
* @example
|
|
186
|
+
* hotUpdate.getVersionInfo(function(info) {
|
|
187
|
+
* console.log('Current:', info.installedVersion || info.appBundleVersion);
|
|
188
|
+
* });
|
|
189
|
+
*/
|
|
190
|
+
getVersionInfo: function(callback) {
|
|
191
|
+
exec(
|
|
192
|
+
function(info) {
|
|
193
|
+
if (callback) callback(info);
|
|
194
|
+
},
|
|
195
|
+
function(error) {
|
|
196
|
+
if (callback) callback({error: error});
|
|
197
|
+
},
|
|
198
|
+
'HotUpdates',
|
|
199
|
+
'getVersionInfo',
|
|
200
|
+
[]
|
|
201
|
+
);
|
|
209
202
|
}
|
|
210
203
|
};
|
|
211
204
|
|