@capawesome/cordova-live-update 0.1.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.
Files changed (103) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1113 -0
  3. package/dist/docs.json +1654 -0
  4. package/dist/esm/definitions.d.ts +788 -0
  5. package/dist/esm/definitions.js +7 -0
  6. package/dist/esm/definitions.js.map +1 -0
  7. package/dist/esm/exec.d.ts +1 -0
  8. package/dist/esm/exec.js +8 -0
  9. package/dist/esm/exec.js.map +1 -0
  10. package/dist/esm/index.d.ts +4 -0
  11. package/dist/esm/index.js +46 -0
  12. package/dist/esm/index.js.map +1 -0
  13. package/dist/plugin.js +56 -0
  14. package/dist/plugin.js.map +1 -0
  15. package/package.json +93 -0
  16. package/plugin.xml +268 -0
  17. package/src/android/capawesome-cordova-live-update.gradle +12 -0
  18. package/src/android/capawesome-live-update.xml +5 -0
  19. package/src/android/io/capawesome/cordova/plugins/liveupdate/LiveUpdate.java +1480 -0
  20. package/src/android/io/capawesome/cordova/plugins/liveupdate/LiveUpdateConfig.java +105 -0
  21. package/src/android/io/capawesome/cordova/plugins/liveupdate/LiveUpdateHttpClient.java +114 -0
  22. package/src/android/io/capawesome/cordova/plugins/liveupdate/LiveUpdatePathHandler.java +96 -0
  23. package/src/android/io/capawesome/cordova/plugins/liveupdate/LiveUpdatePlugin.java +550 -0
  24. package/src/android/io/capawesome/cordova/plugins/liveupdate/LiveUpdatePreferences.java +151 -0
  25. package/src/android/io/capawesome/cordova/plugins/liveupdate/classes/Manifest.java +58 -0
  26. package/src/android/io/capawesome/cordova/plugins/liveupdate/classes/ManifestItem.java +37 -0
  27. package/src/android/io/capawesome/cordova/plugins/liveupdate/classes/api/GetChannelsResponseItem.java +28 -0
  28. package/src/android/io/capawesome/cordova/plugins/liveupdate/classes/api/GetLatestBundleResponse.java +74 -0
  29. package/src/android/io/capawesome/cordova/plugins/liveupdate/classes/events/DownloadBundleProgressEvent.java +33 -0
  30. package/src/android/io/capawesome/cordova/plugins/liveupdate/classes/events/NextBundleSetEvent.java +26 -0
  31. package/src/android/io/capawesome/cordova/plugins/liveupdate/classes/options/DeleteBundleOptions.java +18 -0
  32. package/src/android/io/capawesome/cordova/plugins/liveupdate/classes/options/DownloadBundleOptions.java +66 -0
  33. package/src/android/io/capawesome/cordova/plugins/liveupdate/classes/options/FetchChannelsOptions.java +39 -0
  34. package/src/android/io/capawesome/cordova/plugins/liveupdate/classes/options/FetchLatestBundleOptions.java +25 -0
  35. package/src/android/io/capawesome/cordova/plugins/liveupdate/classes/options/SetChannelOptions.java +18 -0
  36. package/src/android/io/capawesome/cordova/plugins/liveupdate/classes/options/SetConfigOptions.java +20 -0
  37. package/src/android/io/capawesome/cordova/plugins/liveupdate/classes/options/SetCustomIdOptions.java +18 -0
  38. package/src/android/io/capawesome/cordova/plugins/liveupdate/classes/options/SetNextBundleOptions.java +21 -0
  39. package/src/android/io/capawesome/cordova/plugins/liveupdate/classes/options/SyncOptions.java +25 -0
  40. package/src/android/io/capawesome/cordova/plugins/liveupdate/classes/results/ChannelResult.java +29 -0
  41. package/src/android/io/capawesome/cordova/plugins/liveupdate/classes/results/FetchChannelsResult.java +29 -0
  42. package/src/android/io/capawesome/cordova/plugins/liveupdate/classes/results/FetchLatestBundleResult.java +69 -0
  43. package/src/android/io/capawesome/cordova/plugins/liveupdate/classes/results/GetBlockedBundlesResult.java +28 -0
  44. package/src/android/io/capawesome/cordova/plugins/liveupdate/classes/results/GetBundlesResult.java +28 -0
  45. package/src/android/io/capawesome/cordova/plugins/liveupdate/classes/results/GetChannelResult.java +22 -0
  46. package/src/android/io/capawesome/cordova/plugins/liveupdate/classes/results/GetConfigResult.java +40 -0
  47. package/src/android/io/capawesome/cordova/plugins/liveupdate/classes/results/GetCurrentBundleResult.java +22 -0
  48. package/src/android/io/capawesome/cordova/plugins/liveupdate/classes/results/GetCustomIdResult.java +22 -0
  49. package/src/android/io/capawesome/cordova/plugins/liveupdate/classes/results/GetDeviceIdResult.java +22 -0
  50. package/src/android/io/capawesome/cordova/plugins/liveupdate/classes/results/GetDownloadedBundlesResult.java +28 -0
  51. package/src/android/io/capawesome/cordova/plugins/liveupdate/classes/results/GetNextBundleResult.java +22 -0
  52. package/src/android/io/capawesome/cordova/plugins/liveupdate/classes/results/GetVersionCodeResult.java +21 -0
  53. package/src/android/io/capawesome/cordova/plugins/liveupdate/classes/results/GetVersionNameResult.java +22 -0
  54. package/src/android/io/capawesome/cordova/plugins/liveupdate/classes/results/IsSyncingResult.java +27 -0
  55. package/src/android/io/capawesome/cordova/plugins/liveupdate/classes/results/ReadyResult.java +32 -0
  56. package/src/android/io/capawesome/cordova/plugins/liveupdate/classes/results/SyncResult.java +22 -0
  57. package/src/android/io/capawesome/cordova/plugins/liveupdate/enums/ArtifactType.java +6 -0
  58. package/src/android/io/capawesome/cordova/plugins/liveupdate/interfaces/Callback.java +5 -0
  59. package/src/android/io/capawesome/cordova/plugins/liveupdate/interfaces/DownloadProgressCallback.java +5 -0
  60. package/src/android/io/capawesome/cordova/plugins/liveupdate/interfaces/EmptyCallback.java +5 -0
  61. package/src/android/io/capawesome/cordova/plugins/liveupdate/interfaces/NonEmptyCallback.java +7 -0
  62. package/src/android/io/capawesome/cordova/plugins/liveupdate/interfaces/Result.java +8 -0
  63. package/src/ios/LiveUpdate.swift +895 -0
  64. package/src/ios/LiveUpdateArtifactType.swift +4 -0
  65. package/src/ios/LiveUpdateChannelResult.swift +18 -0
  66. package/src/ios/LiveUpdateConfig.swift +11 -0
  67. package/src/ios/LiveUpdateDeleteBundleOptions.swift +13 -0
  68. package/src/ios/LiveUpdateDownloadBundleOptions.swift +41 -0
  69. package/src/ios/LiveUpdateDownloadBundleProgressEvent.swift +24 -0
  70. package/src/ios/LiveUpdateError.swift +62 -0
  71. package/src/ios/LiveUpdateFetchChannelsOptions.swift +25 -0
  72. package/src/ios/LiveUpdateFetchChannelsResult.swift +15 -0
  73. package/src/ios/LiveUpdateFetchLatestBundleOptions.swift +17 -0
  74. package/src/ios/LiveUpdateFetchLatestBundleResult.swift +42 -0
  75. package/src/ios/LiveUpdateGetBlockedBundlesResult.swift +15 -0
  76. package/src/ios/LiveUpdateGetBundlesResult.swift +15 -0
  77. package/src/ios/LiveUpdateGetChannelResult.swift +15 -0
  78. package/src/ios/LiveUpdateGetChannelsResponseItem.swift +4 -0
  79. package/src/ios/LiveUpdateGetConfigResult.swift +18 -0
  80. package/src/ios/LiveUpdateGetCurrentBundleResult.swift +15 -0
  81. package/src/ios/LiveUpdateGetCustomIdResult.swift +15 -0
  82. package/src/ios/LiveUpdateGetDeviceIdResult.swift +15 -0
  83. package/src/ios/LiveUpdateGetDownloadedBundlesResult.swift +15 -0
  84. package/src/ios/LiveUpdateGetLatestBundleResponse.swift +8 -0
  85. package/src/ios/LiveUpdateGetNextBundleResult.swift +15 -0
  86. package/src/ios/LiveUpdateGetVersionCodeResult.swift +15 -0
  87. package/src/ios/LiveUpdateGetVersionNameResult.swift +15 -0
  88. package/src/ios/LiveUpdateHttpClient.swift +58 -0
  89. package/src/ios/LiveUpdateIsSyncingResult.swift +15 -0
  90. package/src/ios/LiveUpdateManifest.swift +19 -0
  91. package/src/ios/LiveUpdateManifestItem.swift +5 -0
  92. package/src/ios/LiveUpdateNextBundleSetEvent.swift +15 -0
  93. package/src/ios/LiveUpdatePlugin.swift +521 -0
  94. package/src/ios/LiveUpdatePreferences.swift +116 -0
  95. package/src/ios/LiveUpdateReadyResult.swift +21 -0
  96. package/src/ios/LiveUpdateResult.swift +5 -0
  97. package/src/ios/LiveUpdateSchemeHandler.swift +286 -0
  98. package/src/ios/LiveUpdateSetChannelOptions.swift +13 -0
  99. package/src/ios/LiveUpdateSetConfigOptions.swift +13 -0
  100. package/src/ios/LiveUpdateSetCustomIdOptions.swift +13 -0
  101. package/src/ios/LiveUpdateSetNextBundleOptions.swift +13 -0
  102. package/src/ios/LiveUpdateSyncOptions.swift +17 -0
  103. package/src/ios/LiveUpdateSyncResult.swift +15 -0
@@ -0,0 +1,550 @@
1
+ package io.capawesome.cordova.plugins.liveupdate;
2
+
3
+ import android.content.Context;
4
+ import android.content.res.Resources;
5
+ import android.util.Log;
6
+ import androidx.annotation.NonNull;
7
+ import androidx.annotation.Nullable;
8
+ import io.capawesome.cordova.plugins.liveupdate.classes.events.DownloadBundleProgressEvent;
9
+ import io.capawesome.cordova.plugins.liveupdate.classes.events.NextBundleSetEvent;
10
+ import io.capawesome.cordova.plugins.liveupdate.classes.options.DeleteBundleOptions;
11
+ import io.capawesome.cordova.plugins.liveupdate.classes.options.DownloadBundleOptions;
12
+ import io.capawesome.cordova.plugins.liveupdate.classes.options.FetchChannelsOptions;
13
+ import io.capawesome.cordova.plugins.liveupdate.classes.options.FetchLatestBundleOptions;
14
+ import io.capawesome.cordova.plugins.liveupdate.classes.options.SetChannelOptions;
15
+ import io.capawesome.cordova.plugins.liveupdate.classes.options.SetConfigOptions;
16
+ import io.capawesome.cordova.plugins.liveupdate.classes.options.SetCustomIdOptions;
17
+ import io.capawesome.cordova.plugins.liveupdate.classes.options.SetNextBundleOptions;
18
+ import io.capawesome.cordova.plugins.liveupdate.classes.options.SyncOptions;
19
+ import io.capawesome.cordova.plugins.liveupdate.classes.results.FetchChannelsResult;
20
+ import io.capawesome.cordova.plugins.liveupdate.classes.results.FetchLatestBundleResult;
21
+ import io.capawesome.cordova.plugins.liveupdate.classes.results.GetBlockedBundlesResult;
22
+ import io.capawesome.cordova.plugins.liveupdate.classes.results.GetConfigResult;
23
+ import io.capawesome.cordova.plugins.liveupdate.classes.results.GetCurrentBundleResult;
24
+ import io.capawesome.cordova.plugins.liveupdate.classes.results.GetDownloadedBundlesResult;
25
+ import io.capawesome.cordova.plugins.liveupdate.classes.results.GetNextBundleResult;
26
+ import io.capawesome.cordova.plugins.liveupdate.classes.results.IsSyncingResult;
27
+ import io.capawesome.cordova.plugins.liveupdate.interfaces.EmptyCallback;
28
+ import io.capawesome.cordova.plugins.liveupdate.interfaces.NonEmptyCallback;
29
+ import io.capawesome.cordova.plugins.liveupdate.interfaces.Result;
30
+ import java.util.Iterator;
31
+ import java.util.Map;
32
+ import java.util.concurrent.ConcurrentHashMap;
33
+ import org.apache.cordova.CallbackContext;
34
+ import org.apache.cordova.CordovaPlugin;
35
+ import org.apache.cordova.CordovaPluginPathHandler;
36
+ import org.apache.cordova.PluginResult;
37
+ import org.json.JSONArray;
38
+ import org.json.JSONException;
39
+ import org.json.JSONObject;
40
+
41
+ public class LiveUpdatePlugin extends CordovaPlugin {
42
+
43
+ public static final String TAG = "LiveUpdate";
44
+ public static final String VERSION = "0.1.0";
45
+ public static final String SHARED_PREFERENCES_NAME = "CapawesomeLiveUpdate"; // DO NOT CHANGE
46
+ public static final String ERROR_APP_ID_MISSING = "appId must be configured.";
47
+ public static final String ERROR_BUNDLE_EXISTS = "bundle already exists.";
48
+ public static final String ERROR_BUNDLE_ID_MISSING = "bundleId must be provided.";
49
+ public static final String ERROR_BUNDLE_INDEX_HTML_MISSING = "The bundle does not contain an index.html file.";
50
+ public static final String ERROR_BUNDLE_NOT_FOUND = "bundle not found.";
51
+ public static final String ERROR_CHECKSUM_CALCULATION_FAILED = "Failed to calculate checksum.";
52
+ public static final String ERROR_CHECKSUM_MISMATCH = "Checksum mismatch.";
53
+ public static final String ERROR_CUSTOM_ID_MISSING = "customId must be provided.";
54
+ public static final String ERROR_DOWNLOAD_FAILED = "Bundle could not be downloaded.";
55
+ public static final String ERROR_HTTP_TIMEOUT = "Request timed out.";
56
+ public static final String ERROR_URL_MISSING = "url must be provided.";
57
+ public static final String ERROR_SIGNATURE_VERIFICATION_FAILED = "Signature verification failed.";
58
+ public static final String ERROR_PUBLIC_KEY_INVALID = "Invalid public key.";
59
+ public static final String ERROR_SIGNATURE_MISSING = "Bundle does not contain a signature.";
60
+ public static final String ERROR_SYNC_IN_PROGRESS = "Sync is already in progress.";
61
+ public static final String ERROR_UNKNOWN_ERROR = "An unknown error has occurred.";
62
+ public static final String ERROR_PLUGIN_NOT_INITIALIZED = "LiveUpdate plugin failed to initialize.";
63
+ public static final String ERROR_LISTENER_ID_MISSING = "listenerId must be provided.";
64
+ public static final String EVENT_DOWNLOAD_BUNDLE_PROGRESS = "downloadBundleProgress";
65
+ public static final String EVENT_NEXT_BUNDLE_SET = "nextBundleSet";
66
+
67
+ @Nullable
68
+ private LiveUpdateConfig config;
69
+
70
+ @Nullable
71
+ private LiveUpdate implementation;
72
+
73
+ @Nullable
74
+ private LiveUpdatePathHandler pathHandler;
75
+
76
+ @Nullable
77
+ private CordovaPluginPathHandler cordovaPathHandler;
78
+
79
+ private final Map<String, ListenerRegistration> listeners = new ConcurrentHashMap<>();
80
+
81
+ private static final class ListenerRegistration {
82
+
83
+ @NonNull
84
+ final String eventName;
85
+
86
+ @NonNull
87
+ final CallbackContext callback;
88
+
89
+ ListenerRegistration(@NonNull String eventName, @NonNull CallbackContext callback) {
90
+ this.eventName = eventName;
91
+ this.callback = callback;
92
+ }
93
+ }
94
+
95
+ @Override
96
+ protected void pluginInitialize() {
97
+ super.pluginInitialize();
98
+ try {
99
+ config = loadLiveUpdateConfig();
100
+ if (pathHandler == null) {
101
+ pathHandler = new LiveUpdatePathHandler();
102
+ }
103
+ implementation = new LiveUpdate(config, this, pathHandler);
104
+ } catch (Exception exception) {
105
+ Log.e(TAG, "Failed to initialize LiveUpdate plugin: " + exception.getMessage(), exception);
106
+ }
107
+ }
108
+
109
+ @Override
110
+ public CordovaPluginPathHandler getPathHandler() {
111
+ if (pathHandler == null) {
112
+ pathHandler = new LiveUpdatePathHandler();
113
+ }
114
+ if (cordovaPathHandler == null) {
115
+ cordovaPathHandler = new CordovaPluginPathHandler(pathHandler);
116
+ }
117
+ return cordovaPathHandler;
118
+ }
119
+
120
+ @Override
121
+ public void onResume(boolean multitasking) {
122
+ super.onResume(multitasking);
123
+ if (implementation != null) {
124
+ implementation.handleOnResume();
125
+ }
126
+ }
127
+
128
+ @Override
129
+ public boolean execute(String action, JSONArray args, CallbackContext callbackContext) {
130
+ if (implementation == null || config == null) {
131
+ callbackContext.error(ERROR_PLUGIN_NOT_INITIALIZED);
132
+ return true;
133
+ }
134
+ try {
135
+ switch (action) {
136
+ case "clearBlockedBundles":
137
+ implementation.clearBlockedBundles();
138
+ resolve(callbackContext);
139
+ return true;
140
+ case "deleteBundle":
141
+ executeDeleteBundle(args, callbackContext);
142
+ return true;
143
+ case "downloadBundle":
144
+ executeDownloadBundle(args, callbackContext);
145
+ return true;
146
+ case "fetchChannels":
147
+ executeFetchChannels(args, callbackContext);
148
+ return true;
149
+ case "fetchLatestBundle":
150
+ executeFetchLatestBundle(args, callbackContext);
151
+ return true;
152
+ case "getBlockedBundles":
153
+ implementation.getBlockedBundles(resultCallback(callbackContext));
154
+ return true;
155
+ case "getBundles":
156
+ implementation.getBundles(resultCallback(callbackContext));
157
+ return true;
158
+ case "getChannel":
159
+ implementation.getChannel(resultCallback(callbackContext));
160
+ return true;
161
+ case "getConfig":
162
+ implementation.getConfig(resultCallback(callbackContext));
163
+ return true;
164
+ case "getCurrentBundle":
165
+ implementation.getCurrentBundle(resultCallback(callbackContext));
166
+ return true;
167
+ case "getCustomId":
168
+ implementation.getCustomId(resultCallback(callbackContext));
169
+ return true;
170
+ case "getDeviceId":
171
+ implementation.getDeviceId(resultCallback(callbackContext));
172
+ return true;
173
+ case "getDownloadedBundles":
174
+ implementation.getDownloadedBundles(resultCallback(callbackContext));
175
+ return true;
176
+ case "getNextBundle":
177
+ implementation.getNextBundle(resultCallback(callbackContext));
178
+ return true;
179
+ case "getVersionCode":
180
+ implementation.getVersionCode(resultCallback(callbackContext));
181
+ return true;
182
+ case "getVersionName":
183
+ implementation.getVersionName(resultCallback(callbackContext));
184
+ return true;
185
+ case "isSyncing":
186
+ implementation.isSyncing(resultCallback(callbackContext));
187
+ return true;
188
+ case "ready":
189
+ implementation.ready(resultCallback(callbackContext));
190
+ return true;
191
+ case "reload":
192
+ implementation.reload();
193
+ resolve(callbackContext);
194
+ return true;
195
+ case "reset":
196
+ implementation.reset();
197
+ resolve(callbackContext);
198
+ return true;
199
+ case "resetConfig":
200
+ implementation.resetConfig();
201
+ resolve(callbackContext);
202
+ return true;
203
+ case "setChannel":
204
+ executeSetChannel(args, callbackContext);
205
+ return true;
206
+ case "setConfig":
207
+ executeSetConfig(args, callbackContext);
208
+ return true;
209
+ case "setCustomId":
210
+ executeSetCustomId(args, callbackContext);
211
+ return true;
212
+ case "setNextBundle":
213
+ executeSetNextBundle(args, callbackContext);
214
+ return true;
215
+ case "sync":
216
+ executeSync(args, callbackContext);
217
+ return true;
218
+ case "addListener":
219
+ executeAddListener(args, callbackContext);
220
+ return true;
221
+ case "removeListener":
222
+ executeRemoveListener(args, callbackContext);
223
+ return true;
224
+ case "removeAllListeners":
225
+ executeRemoveAllListeners(callbackContext);
226
+ return true;
227
+ default:
228
+ return false;
229
+ }
230
+ } catch (Exception exception) {
231
+ reject(callbackContext, exception);
232
+ return true;
233
+ }
234
+ }
235
+
236
+ private void executeDeleteBundle(JSONArray args, CallbackContext callbackContext) throws JSONException {
237
+ JSONObject options = args.optJSONObject(0);
238
+ String bundleId = options == null ? null : (options.isNull("bundleId") ? null : options.optString("bundleId", null));
239
+ if (bundleId == null) {
240
+ callbackContext.error(ERROR_BUNDLE_ID_MISSING);
241
+ return;
242
+ }
243
+ implementation.deleteBundle(new DeleteBundleOptions(bundleId), emptyCallback(callbackContext));
244
+ }
245
+
246
+ private void executeDownloadBundle(JSONArray args, CallbackContext callbackContext) throws JSONException {
247
+ JSONObject options = args.optJSONObject(0);
248
+ if (options == null) {
249
+ callbackContext.error(ERROR_BUNDLE_ID_MISSING);
250
+ return;
251
+ }
252
+ String artifactType = options.optString("artifactType", "zip");
253
+ String bundleId = options.isNull("bundleId") ? null : options.optString("bundleId", null);
254
+ if (bundleId == null) {
255
+ callbackContext.error(ERROR_BUNDLE_ID_MISSING);
256
+ return;
257
+ }
258
+ String checksum = options.isNull("checksum") ? null : options.optString("checksum", null);
259
+ String signature = options.isNull("signature") ? null : options.optString("signature", null);
260
+ String url = options.isNull("url") ? null : options.optString("url", null);
261
+ if (url == null) {
262
+ callbackContext.error(ERROR_URL_MISSING);
263
+ return;
264
+ }
265
+ implementation.downloadBundle(
266
+ new DownloadBundleOptions(artifactType, bundleId, checksum, signature, url),
267
+ emptyCallback(callbackContext)
268
+ );
269
+ }
270
+
271
+ private void executeFetchChannels(JSONArray args, CallbackContext callbackContext) throws JSONException {
272
+ if (config.getAppId() == null || config.getAppId().isEmpty()) {
273
+ callbackContext.error(ERROR_APP_ID_MISSING);
274
+ return;
275
+ }
276
+ JSONObject options = args.optJSONObject(0);
277
+ if (options == null) {
278
+ options = new JSONObject();
279
+ }
280
+ implementation.fetchChannels(new FetchChannelsOptions(options), nonEmptyCallback(callbackContext));
281
+ }
282
+
283
+ private void executeFetchLatestBundle(JSONArray args, CallbackContext callbackContext) throws JSONException {
284
+ if (config.getAppId() == null || config.getAppId().isEmpty()) {
285
+ callbackContext.error(ERROR_APP_ID_MISSING);
286
+ return;
287
+ }
288
+ JSONObject options = args.optJSONObject(0);
289
+ if (options == null) {
290
+ options = new JSONObject();
291
+ }
292
+ implementation.fetchLatestBundle(new FetchLatestBundleOptions(options), nonEmptyCallback(callbackContext));
293
+ }
294
+
295
+ private void executeSetChannel(JSONArray args, CallbackContext callbackContext) {
296
+ JSONObject options = args.optJSONObject(0);
297
+ String channel = options == null || options.isNull("channel") ? null : options.optString("channel", null);
298
+ implementation.setChannel(new SetChannelOptions(channel), emptyCallback(callbackContext));
299
+ }
300
+
301
+ private void executeSetConfig(JSONArray args, CallbackContext callbackContext) throws JSONException {
302
+ JSONObject options = args.optJSONObject(0);
303
+ if (options == null) {
304
+ options = new JSONObject();
305
+ }
306
+ implementation.setConfig(new SetConfigOptions(options));
307
+ resolve(callbackContext);
308
+ }
309
+
310
+ private void executeSetCustomId(JSONArray args, CallbackContext callbackContext) {
311
+ JSONObject options = args.optJSONObject(0);
312
+ String customId = options == null || options.isNull("customId") ? null : options.optString("customId", null);
313
+ if (customId == null) {
314
+ callbackContext.error(ERROR_CUSTOM_ID_MISSING);
315
+ return;
316
+ }
317
+ implementation.setCustomId(new SetCustomIdOptions(customId), emptyCallback(callbackContext));
318
+ }
319
+
320
+ private void executeSetNextBundle(JSONArray args, CallbackContext callbackContext) throws JSONException {
321
+ JSONObject options = args.optJSONObject(0);
322
+ if (options == null) {
323
+ options = new JSONObject();
324
+ }
325
+ implementation.setNextBundle(new SetNextBundleOptions(options), emptyCallback(callbackContext));
326
+ }
327
+
328
+ private void executeSync(JSONArray args, CallbackContext callbackContext) throws JSONException {
329
+ if (config.getAppId() == null || config.getAppId().isEmpty()) {
330
+ callbackContext.error(ERROR_APP_ID_MISSING);
331
+ return;
332
+ }
333
+ JSONObject options = args.optJSONObject(0);
334
+ if (options == null) {
335
+ options = new JSONObject();
336
+ }
337
+ implementation.sync(new SyncOptions(options), nonEmptyCallback(callbackContext));
338
+ }
339
+
340
+ private void executeAddListener(JSONArray args, CallbackContext callbackContext) throws JSONException {
341
+ String eventName = args.optString(0, null);
342
+ String listenerId = args.optString(1, null);
343
+ if (eventName == null || listenerId == null) {
344
+ callbackContext.error(ERROR_LISTENER_ID_MISSING);
345
+ return;
346
+ }
347
+ listeners.put(listenerId, new ListenerRegistration(eventName, callbackContext));
348
+ // Keep the callback alive so we can deliver events to it later.
349
+ PluginResult ack = new PluginResult(PluginResult.Status.NO_RESULT);
350
+ ack.setKeepCallback(true);
351
+ callbackContext.sendPluginResult(ack);
352
+ }
353
+
354
+ private void executeRemoveListener(JSONArray args, CallbackContext callbackContext) throws JSONException {
355
+ JSONObject options = args.optJSONObject(0);
356
+ String listenerId = options == null || options.isNull("listenerId") ? null : options.optString("listenerId", null);
357
+ if (listenerId == null) {
358
+ callbackContext.error(ERROR_LISTENER_ID_MISSING);
359
+ return;
360
+ }
361
+ ListenerRegistration entry = listeners.remove(listenerId);
362
+ if (entry != null) {
363
+ releaseCallback(entry.callback);
364
+ }
365
+ resolve(callbackContext);
366
+ }
367
+
368
+ private void executeRemoveAllListeners(CallbackContext callbackContext) {
369
+ Iterator<Map.Entry<String, ListenerRegistration>> it = listeners.entrySet().iterator();
370
+ while (it.hasNext()) {
371
+ ListenerRegistration entry = it.next().getValue();
372
+ releaseCallback(entry.callback);
373
+ it.remove();
374
+ }
375
+ resolve(callbackContext);
376
+ }
377
+
378
+ public void notifyDownloadBundleProgressListeners(@NonNull DownloadBundleProgressEvent event) {
379
+ try {
380
+ notifyListeners(EVENT_DOWNLOAD_BUNDLE_PROGRESS, event.toJSObject());
381
+ } catch (JSONException e) {
382
+ Log.e(TAG, "Failed to serialize downloadBundleProgress event: " + e.getMessage(), e);
383
+ }
384
+ }
385
+
386
+ public void notifyNextBundleSetListeners(@NonNull NextBundleSetEvent event) {
387
+ try {
388
+ notifyListeners(EVENT_NEXT_BUNDLE_SET, event.toJSObject());
389
+ } catch (JSONException e) {
390
+ Log.e(TAG, "Failed to serialize nextBundleSet event: " + e.getMessage(), e);
391
+ }
392
+ }
393
+
394
+ private void notifyListeners(@NonNull String eventName, @NonNull JSONObject data) {
395
+ for (ListenerRegistration entry : listeners.values()) {
396
+ if (!entry.eventName.equals(eventName)) {
397
+ continue;
398
+ }
399
+ PluginResult result = new PluginResult(PluginResult.Status.OK, data);
400
+ result.setKeepCallback(true);
401
+ entry.callback.sendPluginResult(result);
402
+ }
403
+ }
404
+
405
+ public Context getContext() {
406
+ return cordova.getActivity().getApplicationContext();
407
+ }
408
+
409
+ public void reloadWebView() {
410
+ cordova
411
+ .getActivity()
412
+ .runOnUiThread(() -> {
413
+ if (webView != null && webView.getView() instanceof android.webkit.WebView) {
414
+ ((android.webkit.WebView) webView.getView()).reload();
415
+ }
416
+ });
417
+ }
418
+
419
+ private void releaseCallback(@NonNull CallbackContext callback) {
420
+ PluginResult result = new PluginResult(PluginResult.Status.NO_RESULT);
421
+ result.setKeepCallback(false);
422
+ callback.sendPluginResult(result);
423
+ }
424
+
425
+ private void resolve(@NonNull CallbackContext callbackContext) {
426
+ callbackContext.success();
427
+ }
428
+
429
+ private void resolve(@NonNull CallbackContext callbackContext, @NonNull JSONObject result) {
430
+ callbackContext.success(result);
431
+ }
432
+
433
+ private void reject(@NonNull CallbackContext callbackContext, @NonNull Exception exception) {
434
+ String message = exception.getMessage();
435
+ if (exception instanceof java.net.SocketTimeoutException) {
436
+ message = ERROR_HTTP_TIMEOUT;
437
+ } else if (message == null) {
438
+ message = ERROR_UNKNOWN_ERROR;
439
+ }
440
+ Log.e(TAG, message, exception);
441
+ callbackContext.error(message);
442
+ }
443
+
444
+ private EmptyCallback emptyCallback(@NonNull CallbackContext callbackContext) {
445
+ return new EmptyCallback() {
446
+ @Override
447
+ public void success() {
448
+ resolve(callbackContext);
449
+ }
450
+
451
+ @Override
452
+ public void error(@NonNull Exception exception) {
453
+ reject(callbackContext, exception);
454
+ }
455
+ };
456
+ }
457
+
458
+ private <T extends Result> NonEmptyCallback<T> nonEmptyCallback(@NonNull CallbackContext callbackContext) {
459
+ return new NonEmptyCallback<T>() {
460
+ @Override
461
+ public void success(@NonNull T result) {
462
+ try {
463
+ resolve(callbackContext, result.toJSObject());
464
+ } catch (JSONException e) {
465
+ reject(callbackContext, e);
466
+ }
467
+ }
468
+
469
+ @Override
470
+ public void error(@NonNull Exception exception) {
471
+ reject(callbackContext, exception);
472
+ }
473
+ };
474
+ }
475
+
476
+ private <T extends Result> NonEmptyCallback<T> resultCallback(@NonNull CallbackContext callbackContext) {
477
+ return nonEmptyCallback(callbackContext);
478
+ }
479
+
480
+ @NonNull
481
+ private LiveUpdateConfig loadLiveUpdateConfig() {
482
+ LiveUpdateConfig cfg = new LiveUpdateConfig();
483
+ Context ctx = getContext();
484
+ Resources res = ctx.getResources();
485
+ String pkg = ctx.getPackageName();
486
+
487
+ String appId = readStringRes(res, pkg, "capawesome_live_update_app_id");
488
+ if (appId != null) {
489
+ cfg.setAppId(appId);
490
+ }
491
+ String defaultChannel = readStringRes(res, pkg, "capawesome_live_update_default_channel");
492
+ if (defaultChannel != null) {
493
+ cfg.setDefaultChannel(defaultChannel);
494
+ }
495
+ String autoUpdateStrategy = readStringRes(res, pkg, "capawesome_live_update_auto_update_strategy");
496
+ if (autoUpdateStrategy != null) {
497
+ cfg.setAutoUpdateStrategy(autoUpdateStrategy);
498
+ }
499
+ String publicKey = readStringRes(res, pkg, "capawesome_live_update_public_key");
500
+ if (publicKey != null) {
501
+ cfg.setPublicKey(publicKey);
502
+ }
503
+ String serverDomain = readStringRes(res, pkg, "capawesome_live_update_server_domain");
504
+ if (serverDomain != null) {
505
+ cfg.setServerDomain(serverDomain);
506
+ }
507
+ cfg.setHttpTimeout(parseIntSafe(readStringRes(res, pkg, "capawesome_live_update_http_timeout"), cfg.getHttpTimeout()));
508
+ cfg.setReadyTimeout(parseIntSafe(readStringRes(res, pkg, "capawesome_live_update_ready_timeout"), cfg.getReadyTimeout()));
509
+ cfg.setAutoDeleteBundles(
510
+ parseBoolSafe(readStringRes(res, pkg, "capawesome_live_update_auto_delete_bundles"), cfg.getAutoDeleteBundles())
511
+ );
512
+ cfg.setAutoBlockRolledBackBundles(
513
+ parseBoolSafe(
514
+ readStringRes(res, pkg, "capawesome_live_update_auto_block_rolled_back_bundles"),
515
+ cfg.getAutoBlockRolledBackBundles()
516
+ )
517
+ );
518
+ return cfg;
519
+ }
520
+
521
+ @Nullable
522
+ static String readStringRes(@NonNull Resources res, @NonNull String pkg, @NonNull String key) {
523
+ int resId = res.getIdentifier(key, "string", pkg);
524
+ if (resId == 0) {
525
+ return null;
526
+ }
527
+ // Cordova injects a single-space sentinel for "unset" preferences (see
528
+ // plugin.xml). Treat whitespace-only values as null.
529
+ String value = res.getString(resId).trim();
530
+ return value.isEmpty() ? null : value;
531
+ }
532
+
533
+ private static int parseIntSafe(@Nullable String value, int fallback) {
534
+ if (value == null || value.isEmpty()) {
535
+ return fallback;
536
+ }
537
+ try {
538
+ return Integer.parseInt(value);
539
+ } catch (NumberFormatException e) {
540
+ return fallback;
541
+ }
542
+ }
543
+
544
+ private static boolean parseBoolSafe(@Nullable String value, boolean fallback) {
545
+ if (value == null || value.isEmpty()) {
546
+ return fallback;
547
+ }
548
+ return Boolean.parseBoolean(value);
549
+ }
550
+ }
@@ -0,0 +1,151 @@
1
+ package io.capawesome.cordova.plugins.liveupdate;
2
+
3
+ import android.app.Activity;
4
+ import android.content.Context;
5
+ import android.content.SharedPreferences;
6
+ import androidx.annotation.NonNull;
7
+ import androidx.annotation.Nullable;
8
+
9
+ public class LiveUpdatePreferences {
10
+
11
+ @NonNull
12
+ private final Context context;
13
+
14
+ @NonNull
15
+ private final SharedPreferences.Editor settingsEditor;
16
+
17
+ private final String appIdKey = "appId"; // DO NOT CHANGE
18
+ private final String blockedBundleIdsKey = "blockedBundleIds"; // DO NOT CHANGE
19
+ private final String channelKey = "channel"; // DO NOT CHANGE
20
+ private final String deviceIdKey = "deviceId"; // DO NOT CHANGE
21
+ private final String customIdKey = "customId"; // DO NOT CHANGE
22
+ private final String lastVersionCodeKey = "lastVersionCode"; // DO NOT CHANGE
23
+ private final String nextBundleIdKey = "nextBundleId"; // DO NOT CHANGE
24
+ private final String previousBundleIdKey = "previousBundleId"; // DO NOT CHANGE
25
+
26
+ public LiveUpdatePreferences(@NonNull Context context) {
27
+ this.context = context;
28
+ this.settingsEditor = context.getSharedPreferences(LiveUpdatePlugin.SHARED_PREFERENCES_NAME, Activity.MODE_PRIVATE).edit();
29
+ }
30
+
31
+ @Nullable
32
+ public String getAppId() {
33
+ return context.getSharedPreferences(LiveUpdatePlugin.SHARED_PREFERENCES_NAME, Activity.MODE_PRIVATE).getString(appIdKey, null);
34
+ }
35
+
36
+ @Nullable
37
+ public String getChannel() {
38
+ return context.getSharedPreferences(LiveUpdatePlugin.SHARED_PREFERENCES_NAME, Activity.MODE_PRIVATE).getString(channelKey, null);
39
+ }
40
+
41
+ @Nullable
42
+ public String getCustomId() {
43
+ return context.getSharedPreferences(LiveUpdatePlugin.SHARED_PREFERENCES_NAME, Activity.MODE_PRIVATE).getString(customIdKey, null);
44
+ }
45
+
46
+ @Nullable
47
+ public String getDeviceIdForApp(@Nullable String appId) {
48
+ if (appId == null) {
49
+ return context
50
+ .getSharedPreferences(LiveUpdatePlugin.SHARED_PREFERENCES_NAME, Activity.MODE_PRIVATE)
51
+ .getString(deviceIdKey, null);
52
+ } else {
53
+ return context
54
+ .getSharedPreferences(LiveUpdatePlugin.SHARED_PREFERENCES_NAME, Activity.MODE_PRIVATE)
55
+ .getString(deviceIdKey + "_" + appId, null);
56
+ }
57
+ }
58
+
59
+ public int getLastVersionCode() {
60
+ return context.getSharedPreferences(LiveUpdatePlugin.SHARED_PREFERENCES_NAME, Activity.MODE_PRIVATE).getInt(lastVersionCodeKey, -1);
61
+ }
62
+
63
+ @Nullable
64
+ public String getNextBundleId() {
65
+ return context
66
+ .getSharedPreferences(LiveUpdatePlugin.SHARED_PREFERENCES_NAME, Activity.MODE_PRIVATE)
67
+ .getString(nextBundleIdKey, null);
68
+ }
69
+
70
+ @Nullable
71
+ public String getPreviousBundleId() {
72
+ return context
73
+ .getSharedPreferences(LiveUpdatePlugin.SHARED_PREFERENCES_NAME, Activity.MODE_PRIVATE)
74
+ .getString(previousBundleIdKey, null);
75
+ }
76
+
77
+ @Nullable
78
+ public String getBlockedBundleIds() {
79
+ return context
80
+ .getSharedPreferences(LiveUpdatePlugin.SHARED_PREFERENCES_NAME, Activity.MODE_PRIVATE)
81
+ .getString(blockedBundleIdsKey, null);
82
+ }
83
+
84
+ public void setAppId(@Nullable String appId) {
85
+ if (appId == null) {
86
+ settingsEditor.remove(appIdKey);
87
+ } else {
88
+ settingsEditor.putString(appIdKey, appId);
89
+ }
90
+ settingsEditor.apply();
91
+ }
92
+
93
+ public void setBlockedBundleIds(@Nullable String blockedBundleIds) {
94
+ if (blockedBundleIds == null) {
95
+ settingsEditor.remove(blockedBundleIdsKey);
96
+ } else {
97
+ settingsEditor.putString(blockedBundleIdsKey, blockedBundleIds);
98
+ }
99
+ settingsEditor.apply();
100
+ }
101
+
102
+ public void setChannel(@Nullable String channel) {
103
+ if (channel == null) {
104
+ settingsEditor.remove(channelKey);
105
+ } else {
106
+ settingsEditor.putString(channelKey, channel);
107
+ }
108
+ settingsEditor.apply();
109
+ }
110
+
111
+ public void setCustomId(@Nullable String customId) {
112
+ if (customId == null) {
113
+ settingsEditor.remove(customIdKey);
114
+ } else {
115
+ settingsEditor.putString(customIdKey, customId);
116
+ }
117
+ settingsEditor.apply();
118
+ }
119
+
120
+ public void setDeviceIdForApp(@Nullable String appId, @NonNull String deviceId) {
121
+ if (appId == null) {
122
+ settingsEditor.putString(deviceIdKey, deviceId);
123
+ } else {
124
+ settingsEditor.putString(deviceIdKey + "_" + appId, deviceId);
125
+ }
126
+ settingsEditor.apply();
127
+ }
128
+
129
+ public void setLastVersionCode(int versionCode) {
130
+ settingsEditor.putInt(lastVersionCodeKey, versionCode);
131
+ settingsEditor.apply();
132
+ }
133
+
134
+ public void setNextBundleId(@Nullable String bundleId) {
135
+ if (bundleId == null) {
136
+ settingsEditor.remove(nextBundleIdKey);
137
+ } else {
138
+ settingsEditor.putString(nextBundleIdKey, bundleId);
139
+ }
140
+ settingsEditor.apply();
141
+ }
142
+
143
+ public void setPreviousBundleId(@Nullable String bundleId) {
144
+ if (bundleId == null) {
145
+ settingsEditor.remove(previousBundleIdKey);
146
+ } else {
147
+ settingsEditor.putString(previousBundleIdKey, bundleId);
148
+ }
149
+ settingsEditor.apply();
150
+ }
151
+ }