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
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* @file HotUpdatesConstants.h
|
|
3
|
+
* @brief Constants for Hot Updates Plugin
|
|
4
|
+
* @details Defines error codes, storage keys, and directory names
|
|
5
|
+
* @version 2.2.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
|
+
|
|
13
|
+
#pragma mark - Error Codes
|
|
14
|
+
|
|
15
|
+
extern NSString * const kErrorUpdateDataRequired;
|
|
16
|
+
extern NSString * const kErrorURLRequired;
|
|
17
|
+
extern NSString * const kErrorDownloadInProgress;
|
|
18
|
+
extern NSString * const kErrorDownloadFailed;
|
|
19
|
+
extern NSString * const kErrorHTTPError;
|
|
20
|
+
extern NSString * const kErrorTempDirError;
|
|
21
|
+
extern NSString * const kErrorExtractionFailed;
|
|
22
|
+
extern NSString * const kErrorWWWNotFound;
|
|
23
|
+
extern NSString * const kErrorNoUpdateReady;
|
|
24
|
+
extern NSString * const kErrorUpdateFilesNotFound;
|
|
25
|
+
extern NSString * const kErrorInstallFailed;
|
|
26
|
+
extern NSString * const kErrorVersionRequired;
|
|
27
|
+
|
|
28
|
+
#pragma mark - Storage Keys
|
|
29
|
+
|
|
30
|
+
extern NSString * const kInstalledVersion;
|
|
31
|
+
extern NSString * const kPendingVersion;
|
|
32
|
+
extern NSString * const kHasPending;
|
|
33
|
+
extern NSString * const kPreviousVersion;
|
|
34
|
+
extern NSString * const kIgnoreList;
|
|
35
|
+
extern NSString * const kCanaryVersion;
|
|
36
|
+
extern NSString * const kDownloadInProgress;
|
|
37
|
+
extern NSString * const kPendingUpdateURL;
|
|
38
|
+
extern NSString * const kPendingUpdateReady;
|
|
39
|
+
|
|
40
|
+
#pragma mark - Directory Names
|
|
41
|
+
|
|
42
|
+
extern NSString * const kWWWDirName;
|
|
43
|
+
extern NSString * const kPreviousWWWDirName;
|
|
44
|
+
extern NSString * const kBackupWWWDirName;
|
|
45
|
+
extern NSString * const kPendingUpdateDirName;
|
|
@@ -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.2.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,192 +1,212 @@
|
|
|
1
1
|
var exec = require('cordova/exec');
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* Cordova Hot Updates Plugin
|
|
4
|
+
* Cordova Hot Updates Plugin v2.1.2
|
|
5
|
+
* Frontend-controlled manual hot updates for iOS
|
|
5
6
|
*
|
|
6
|
-
* Provides
|
|
7
|
-
* using the WebView Reload approach
|
|
7
|
+
* Provides manual over-the-air (OTA) updates for Cordova applications
|
|
8
|
+
* using the WebView Reload approach. All update decisions are controlled
|
|
9
|
+
* by JavaScript - the native plugin only executes commands.
|
|
8
10
|
*
|
|
9
11
|
* Features:
|
|
10
|
-
* -
|
|
11
|
-
* -
|
|
12
|
-
* -
|
|
13
|
-
* -
|
|
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
|
|
14
18
|
* - No App Store approval required for web content updates
|
|
15
19
|
*
|
|
16
|
-
* @version 1.
|
|
20
|
+
* @version 2.1.2
|
|
17
21
|
* @author Mustafin Vladimir
|
|
18
22
|
*/
|
|
19
23
|
var HotUpdates = {
|
|
20
24
|
|
|
21
25
|
/**
|
|
22
|
-
*
|
|
23
|
-
* Returns the currently active version (installed update or bundle version)
|
|
26
|
+
* Download update from server
|
|
24
27
|
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
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)
|
|
27
31
|
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
* function(version) {
|
|
31
|
-
* console.log('Current version:', version);
|
|
32
|
-
* },
|
|
33
|
-
* function(error) {
|
|
34
|
-
* console.error('Error getting version:', error);
|
|
35
|
-
* }
|
|
36
|
-
* );
|
|
37
|
-
*/
|
|
38
|
-
getCurrentVersion: function(successCallback, errorCallback) {
|
|
39
|
-
exec(successCallback, errorCallback, 'HotUpdates', 'getCurrentVersion', []);
|
|
40
|
-
},
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Get pending update information
|
|
44
|
-
* Returns information about downloaded updates waiting to be installed
|
|
45
|
-
*
|
|
46
|
-
* @param {Function} successCallback - Success callback with update info object
|
|
47
|
-
* @param {Function} errorCallback - Error callback
|
|
32
|
+
* If the specified version is already downloaded, returns success without re-downloading.
|
|
33
|
+
* Does NOT check ignoreList - JavaScript controls all installation decisions.
|
|
48
34
|
*
|
|
49
|
-
*
|
|
50
|
-
* -
|
|
51
|
-
* -
|
|
52
|
-
* -
|
|
53
|
-
*
|
|
54
|
-
*
|
|
35
|
+
* @param {Object} options - Update options
|
|
36
|
+
* @param {string} options.url - URL to download ZIP archive (required)
|
|
37
|
+
* @param {string} [options.version] - Version string (optional)
|
|
38
|
+
* @param {Function} callback - Callback function
|
|
39
|
+
* - Called with null on success
|
|
40
|
+
* - Called with {error: {message?: string}} on error
|
|
55
41
|
*
|
|
56
42
|
* @example
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
43
|
+
* window.hotUpdate.getUpdate({
|
|
44
|
+
* url: 'https://your-server.com/updates/2.0.0.zip',
|
|
45
|
+
* version: '2.0.0'
|
|
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
|
|
62
53
|
* }
|
|
63
|
-
*
|
|
64
|
-
* function(error) {
|
|
65
|
-
* console.error('Error getting update info:', error);
|
|
66
|
-
* }
|
|
67
|
-
* );
|
|
54
|
+
* });
|
|
68
55
|
*/
|
|
69
|
-
|
|
70
|
-
|
|
56
|
+
getUpdate: function(options, callback) {
|
|
57
|
+
if (!options || !options.url) {
|
|
58
|
+
if (callback) {
|
|
59
|
+
callback({error: {message: 'URL is required'}});
|
|
60
|
+
}
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
exec(
|
|
65
|
+
function() {
|
|
66
|
+
// Success
|
|
67
|
+
if (callback) callback(null);
|
|
68
|
+
},
|
|
69
|
+
function(error) {
|
|
70
|
+
// Error
|
|
71
|
+
if (callback) callback({error: error});
|
|
72
|
+
},
|
|
73
|
+
'HotUpdates',
|
|
74
|
+
'getUpdate',
|
|
75
|
+
[options]
|
|
76
|
+
);
|
|
71
77
|
},
|
|
72
78
|
|
|
73
79
|
/**
|
|
74
|
-
*
|
|
75
|
-
*
|
|
80
|
+
* Install downloaded update immediately
|
|
81
|
+
*
|
|
82
|
+
* Installs the update that was downloaded via getUpdate().
|
|
83
|
+
* This will:
|
|
84
|
+
* 1. Backup current version to www_previous
|
|
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
|
|
76
89
|
*
|
|
77
|
-
*
|
|
78
|
-
*
|
|
90
|
+
* IMPORTANT: JavaScript MUST call canary(version) within 20 seconds
|
|
91
|
+
* after reload to confirm successful bundle load. Otherwise automatic
|
|
92
|
+
* rollback will occur.
|
|
79
93
|
*
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
* -
|
|
83
|
-
*
|
|
84
|
-
*
|
|
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
|
|
85
99
|
*
|
|
86
100
|
* @example
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
-
* console.log('Update available:', result.availableVersion);
|
|
101
|
+
* window.hotUpdate.forceUpdate(function(error) {
|
|
102
|
+
* if (error) {
|
|
103
|
+
* console.error('Install failed:', error);
|
|
91
104
|
* } else {
|
|
92
|
-
*
|
|
105
|
+
* console.log('Update installing, WebView will reload...');
|
|
106
|
+
* // After reload, MUST call canary() within 20 seconds!
|
|
93
107
|
* }
|
|
94
|
-
*
|
|
95
|
-
* function(error) {
|
|
96
|
-
* console.error('Update check failed:', error);
|
|
97
|
-
* }
|
|
98
|
-
* );
|
|
108
|
+
* });
|
|
99
109
|
*/
|
|
100
|
-
|
|
101
|
-
exec(
|
|
110
|
+
forceUpdate: function(callback) {
|
|
111
|
+
exec(
|
|
112
|
+
function() {
|
|
113
|
+
// Success
|
|
114
|
+
if (callback) callback(null);
|
|
115
|
+
},
|
|
116
|
+
function(error) {
|
|
117
|
+
// Error
|
|
118
|
+
if (callback) callback({error: error});
|
|
119
|
+
},
|
|
120
|
+
'HotUpdates',
|
|
121
|
+
'forceUpdate',
|
|
122
|
+
[]
|
|
123
|
+
);
|
|
102
124
|
},
|
|
103
125
|
|
|
104
126
|
/**
|
|
105
|
-
*
|
|
106
|
-
* Manually triggers download of an available update
|
|
127
|
+
* Confirm successful bundle load (canary check)
|
|
107
128
|
*
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
-
*
|
|
111
|
-
* @param {Function} errorCallback - Error callback
|
|
112
|
-
* @param {Function} progressCallback - Optional progress callback with download percentage
|
|
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.
|
|
113
132
|
*
|
|
114
|
-
*
|
|
115
|
-
*
|
|
116
|
-
*
|
|
117
|
-
*
|
|
118
|
-
* function() {
|
|
119
|
-
* console.log('Download completed, update will install on restart');
|
|
120
|
-
* },
|
|
121
|
-
* function(error) {
|
|
122
|
-
* console.error('Download failed:', error);
|
|
123
|
-
* },
|
|
124
|
-
* function(progress) {
|
|
125
|
-
* console.log('Download progress:', progress + '%');
|
|
126
|
-
* }
|
|
127
|
-
* );
|
|
128
|
-
*/
|
|
129
|
-
downloadUpdate: function(downloadURL, version, successCallback, errorCallback, progressCallback) {
|
|
130
|
-
var callbackId = successCallback ? 'HotUpdates' + Date.now() : null;
|
|
131
|
-
|
|
132
|
-
if (progressCallback) {
|
|
133
|
-
// Register progress callback if provided
|
|
134
|
-
exec(progressCallback, null, 'HotUpdates', 'setProgressCallback', [callbackId]);
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
exec(successCallback, errorCallback, 'HotUpdates', 'downloadUpdate', [downloadURL, version, callbackId]);
|
|
138
|
-
},
|
|
139
|
-
|
|
140
|
-
/**
|
|
141
|
-
* Get plugin configuration
|
|
142
|
-
* Returns current plugin configuration settings
|
|
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
|
|
143
137
|
*
|
|
144
|
-
*
|
|
145
|
-
* @param {Function} errorCallback - Error callback
|
|
138
|
+
* Call this immediately after your app initialization completes.
|
|
146
139
|
*
|
|
147
|
-
*
|
|
148
|
-
* -
|
|
149
|
-
* - checkInterval: number (check interval in milliseconds)
|
|
150
|
-
* - appBundleVersion: string (native app version)
|
|
151
|
-
* - autoDownload: boolean (automatic download enabled)
|
|
140
|
+
* @param {string} version - Version that loaded successfully
|
|
141
|
+
* @param {Function} [callback] - Optional callback (not used, method is synchronous)
|
|
152
142
|
*
|
|
153
143
|
* @example
|
|
154
|
-
*
|
|
155
|
-
*
|
|
156
|
-
*
|
|
157
|
-
* console.log('
|
|
158
|
-
*
|
|
159
|
-
* function(error) {
|
|
160
|
-
* console.error('Error getting config:', error);
|
|
161
|
-
* }
|
|
162
|
-
* );
|
|
144
|
+
* // Call as early as possible after app loads
|
|
145
|
+
* document.addEventListener('deviceready', function() {
|
|
146
|
+
* window.hotUpdate.canary('2.0.0');
|
|
147
|
+
* console.log('Canary confirmed, update successful');
|
|
148
|
+
* }, false);
|
|
163
149
|
*/
|
|
164
|
-
|
|
165
|
-
exec(
|
|
150
|
+
canary: function(version, callback) {
|
|
151
|
+
exec(
|
|
152
|
+
function() {
|
|
153
|
+
if (callback) callback();
|
|
154
|
+
},
|
|
155
|
+
function() {
|
|
156
|
+
if (callback) callback();
|
|
157
|
+
},
|
|
158
|
+
'HotUpdates',
|
|
159
|
+
'canary',
|
|
160
|
+
[version]
|
|
161
|
+
);
|
|
166
162
|
},
|
|
167
163
|
|
|
168
164
|
/**
|
|
169
|
-
*
|
|
170
|
-
* Forces installation of a downloaded update without waiting for next app launch
|
|
171
|
-
* This will restart the application!
|
|
165
|
+
* Get list of problematic versions (information only)
|
|
172
166
|
*
|
|
173
|
-
*
|
|
174
|
-
*
|
|
167
|
+
* Returns array of version strings that failed to load (triggered rollback).
|
|
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
|
|
175
180
|
*
|
|
176
181
|
* @example
|
|
177
|
-
*
|
|
178
|
-
*
|
|
179
|
-
* //
|
|
180
|
-
*
|
|
181
|
-
*
|
|
182
|
-
*
|
|
183
|
-
*
|
|
184
|
-
*
|
|
185
|
-
*
|
|
182
|
+
* window.hotUpdate.getIgnoreList(function(result) {
|
|
183
|
+
* console.log('Problematic versions:', result.versions);
|
|
184
|
+
* // Example: {versions: ['1.9.0', '2.0.1']}
|
|
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
|
|
192
|
+
* }
|
|
193
|
+
* });
|
|
186
194
|
*/
|
|
187
|
-
|
|
188
|
-
exec(
|
|
195
|
+
getIgnoreList: function(callback) {
|
|
196
|
+
exec(
|
|
197
|
+
function(versions) {
|
|
198
|
+
// Success - native returns array of version strings
|
|
199
|
+
if (callback) callback({versions: versions || []});
|
|
200
|
+
},
|
|
201
|
+
function(error) {
|
|
202
|
+
// Error - return empty list
|
|
203
|
+
if (callback) callback({versions: []});
|
|
204
|
+
},
|
|
205
|
+
'HotUpdates',
|
|
206
|
+
'getIgnoreList',
|
|
207
|
+
[]
|
|
208
|
+
);
|
|
189
209
|
}
|
|
190
210
|
};
|
|
191
211
|
|
|
192
|
-
module.exports = HotUpdates;
|
|
212
|
+
module.exports = HotUpdates;
|