@capawesome/capacitor-live-update 8.1.0-dev.c088829.1767373807 → 8.1.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 CHANGED
@@ -13,7 +13,7 @@ Capacitor plugin that allows you to update your app remotely in real-time withou
13
13
  We are proud to offer one of the most complete and feature-rich Capacitor plugins for Over-the-Air (OTA) updates. Here are some of the key features:
14
14
 
15
15
  - 🔋 Supports **Android and iOS**
16
- - ⚡️ **Capacitor 7** support
16
+ - ⚡️ **Capacitor 6/7/8** support
17
17
  - 📦 **Bundle Management**: Download, set, and delete bundles.
18
18
  - ☁️ **Cloud Support**: Use the [Capawesome Cloud](https://cloud.capawesome.io/) to manage your app updates.
19
19
  - 📺 **Channel Support**: Set a channel for the app to manage different versions.
@@ -38,12 +38,8 @@ Missing a feature? Just [open an issue](https://github.com/capawesome-team/capac
38
38
 
39
39
  ## Guides
40
40
 
41
- - [Announcing the Capacitor Live Update Plugin](https://capawesome.io/blog/announcing-the-capacitor-live-update-plugin/)
42
- - [Exploring the Capacitor Live Update API](https://capawesome.io/blog/exploring-the-capacitor-live-update-api/)
43
- - [How Live Updates for Capacitor work](https://capawesome.io/blog/how-live-updates-for-capacitor-work/)
44
- - [How to gradually roll out Capacitor Live Updates](https://capawesome.io/blog/how-to-gradually-roll-out-capacitor-live-updates/#update-a-bundle)
45
- - [How to restrict Capacitor Live Updates to Native Versions](https://capawesome.io/blog/how-to-restrict-capacitor-live-updates-to-native-versions/)
46
- - [Live Updates for Nuxt Capacitor Apps with Capawesome Cloud](https://capawesome.io/blog/live-updates-for-nuxt-capacitor/)
41
+ - [Getting Started with Capawesome Cloud Live Updates](https://capawesome.io/cloud/live-updates/setup/)
42
+ - [Migrating from Ionic Appflow to Capawesome Cloud](https://capawesome.io/blog/migrating-from-ionic-appflow-to-capawesome-cloud/)
47
43
  - [Migrating from App Center to Capawesome Cloud](https://capawesome.io/blog/migrating-from-app-center-to-capawesome-cloud/)
48
44
 
49
45
  ## Installation
@@ -886,13 +882,13 @@ Remove all listeners for this plugin.
886
882
 
887
883
  #### DownloadBundleOptions
888
884
 
889
- | Prop | Type | Description | Default | Since |
890
- | ------------------ | -------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------ | ----- |
891
- | **`artifactType`** | <code>'manifest' \| 'zip'</code> | The artifact type of the bundle. | <code>'zip'</code> | 6.6.0 |
892
- | **`bundleId`** | <code>string</code> | The unique identifier of the bundle. **Attention**: The value `public` is reserved and cannot be used as a bundle identifier. | | 5.0.0 |
893
- | **`checksum`** | <code>string</code> | The checksum of the self-hosted bundle as a SHA-256 hash in base64 format to verify the integrity of the bundle. **Attention**: Only supported for the `zip` artifact type. | | 7.1.0 |
894
- | **`signature`** | <code>string</code> | The signature of the self-hosted bundle as a signed SHA-256 hash in base64 format to verify the integrity of the bundle. **Attention**: Only supported for the `zip` artifact type. | | 7.1.0 |
895
- | **`url`** | <code>string</code> | The URL of the bundle to download. For the `zip` artifact type, the URL must point to a ZIP file. For the `manifest` artifact type, the URL serves as the base URL to download the individual files. For example, if the URL is `https://example.com/download`, the plugin will download the file with the href `index.html` from `https://example.com/download?href=index.html`. To **verify the integrity** of the file, the server should return a `X-Checksum` header with the SHA-256 hash in base64 format. To **verify the signature** of the file, the server should return a `X-Signature` header with the signed SHA-256 hash in base64 format. | | 5.0.0 |
885
+ | Prop | Type | Description | Default | Since |
886
+ | ------------------ | -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------ | ----- |
887
+ | **`artifactType`** | <code>'manifest' \| 'zip'</code> | The artifact type of the bundle. | <code>'zip'</code> | 6.6.0 |
888
+ | **`bundleId`** | <code>string</code> | The unique identifier of the bundle. **Attention**: The value `public` is reserved and cannot be used as a bundle identifier. | | 5.0.0 |
889
+ | **`checksum`** | <code>string</code> | The checksum of the self-hosted bundle as a SHA-256 hash in hex format to verify the integrity of the bundle. **Attention**: Only supported for the `zip` artifact type. | | 7.1.0 |
890
+ | **`signature`** | <code>string</code> | The signature of the self-hosted bundle as a signed SHA-256 hash in base64 format to verify the integrity of the bundle. **Attention**: Only supported for the `zip` artifact type. | | 7.1.0 |
891
+ | **`url`** | <code>string</code> | The URL of the bundle to download. For the `zip` artifact type, the URL must point to a ZIP file. For the `manifest` artifact type, the URL serves as the base URL to download the individual files. For example, if the URL is `https://example.com/download`, the plugin will download the file with the href `index.html` from `https://example.com/download?href=index.html`. To **verify the integrity** of the file, the server should return a `X-Checksum` header with the SHA-256 hash in hex format. To **verify the signature** of the file, the server should return a `X-Signature` header with the signed SHA-256 hash in base64 format. | | 5.0.0 |
896
892
 
897
893
 
898
894
  #### FetchLatestBundleResult
@@ -32,7 +32,7 @@ android {
32
32
  buildTypes {
33
33
  release {
34
34
  minifyEnabled false
35
- proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
35
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
36
36
  }
37
37
  }
38
38
  lintOptions {
@@ -1,7 +1,6 @@
1
1
  package io.capawesome.capacitorjs.plugins.liveupdate;
2
2
 
3
3
  import android.app.Activity;
4
- import android.content.Context;
5
4
  import android.content.SharedPreferences;
6
5
  import android.content.pm.PackageInfo;
7
6
  import android.content.pm.PackageManager;
@@ -14,7 +13,6 @@ import androidx.annotation.Nullable;
14
13
  import com.getcapacitor.Bridge;
15
14
  import com.getcapacitor.Logger;
16
15
  import com.getcapacitor.plugin.WebView;
17
- import io.capawesome.capacitorjs.plugins.liveupdate.classes.CustomExceptions;
18
16
  import io.capawesome.capacitorjs.plugins.liveupdate.classes.Manifest;
19
17
  import io.capawesome.capacitorjs.plugins.liveupdate.classes.ManifestItem;
20
18
  import io.capawesome.capacitorjs.plugins.liveupdate.classes.api.GetLatestBundleResponse;
@@ -46,7 +44,6 @@ import io.capawesome.capacitorjs.plugins.liveupdate.classes.results.SyncResult;
46
44
  import io.capawesome.capacitorjs.plugins.liveupdate.enums.ArtifactType;
47
45
  import io.capawesome.capacitorjs.plugins.liveupdate.interfaces.DownloadProgressCallback;
48
46
  import io.capawesome.capacitorjs.plugins.liveupdate.interfaces.EmptyCallback;
49
- import io.capawesome.capacitorjs.plugins.liveupdate.interfaces.LiveUpdateEventEmitter;
50
47
  import io.capawesome.capacitorjs.plugins.liveupdate.interfaces.NonEmptyCallback;
51
48
  import io.capawesome.capacitorjs.plugins.liveupdate.interfaces.Result;
52
49
  import java.io.File;
@@ -80,27 +77,18 @@ import org.json.JSONObject;
80
77
 
81
78
  public class LiveUpdate {
82
79
 
83
- public static final String TAG = "LiveUpdate";
84
- public static final String VERSION = "8.1.1";
85
-
86
80
  private final long autoUpdateIntervalMs = 15 * 60 * 1000; // 15 minutes
87
81
 
88
- @NonNull
89
- private final Bridge bridge;
90
-
91
82
  @NonNull
92
83
  private final LiveUpdateConfig config;
93
84
 
94
- @NonNull
95
- private final Context context;
96
-
97
85
  private final String defaultWebAssetDir = Bridge.DEFAULT_WEB_ASSET_DIR;
98
86
 
99
87
  @NonNull
100
- private final LiveUpdateEventEmitter eventEmitter;
88
+ private final LiveUpdateHttpClient httpClient;
101
89
 
102
90
  @NonNull
103
- private final LiveUpdateHttpClient httpClient;
91
+ private final LiveUpdatePlugin plugin;
104
92
 
105
93
  @NonNull
106
94
  private final LiveUpdatePreferences preferences;
@@ -117,19 +105,12 @@ public class LiveUpdate {
117
105
  private boolean rollbackPerformed = false;
118
106
  private boolean syncInProgress = false;
119
107
 
120
- public LiveUpdate(
121
- @NonNull Context context,
122
- @NonNull Bridge bridge,
123
- @NonNull LiveUpdateConfig config,
124
- @NonNull LiveUpdateEventEmitter eventEmitter
125
- ) throws PackageManager.NameNotFoundException {
126
- this.context = context;
127
- this.bridge = bridge;
108
+ public LiveUpdate(@NonNull LiveUpdateConfig config, @NonNull LiveUpdatePlugin plugin) throws PackageManager.NameNotFoundException {
128
109
  this.config = config;
129
- this.eventEmitter = eventEmitter;
130
110
  this.httpClient = new LiveUpdateHttpClient(config);
131
- this.preferences = new LiveUpdatePreferences(context);
132
- this.webViewSettingsEditor = context.getSharedPreferences(WebView.WEBVIEW_PREFS_NAME, Activity.MODE_PRIVATE).edit();
111
+ this.plugin = plugin;
112
+ this.preferences = new LiveUpdatePreferences(plugin.getContext());
113
+ this.webViewSettingsEditor = plugin.getContext().getSharedPreferences(WebView.WEBVIEW_PREFS_NAME, Activity.MODE_PRIVATE).edit();
133
114
 
134
115
  // Check version and reset config if version changed
135
116
  checkAndResetConfigIfVersionChanged();
@@ -147,7 +128,7 @@ public class LiveUpdate {
147
128
  String bundleId = options.getBundleId();
148
129
 
149
130
  if (!hasBundleById(bundleId)) {
150
- Exception exception = CustomExceptions.BUNDLE_NOT_FOUND;
131
+ Exception exception = new Exception(LiveUpdatePlugin.ERROR_BUNDLE_NOT_FOUND);
151
132
  callback.error(exception);
152
133
  return;
153
134
  }
@@ -303,9 +284,9 @@ public class LiveUpdate {
303
284
  }
304
285
 
305
286
  public void ready(@NonNull NonEmptyCallback callback) {
306
- Logger.debug(LiveUpdate.TAG, "App is ready.");
287
+ Logger.debug(LiveUpdatePlugin.TAG, "App is ready.");
307
288
  if (config.getReadyTimeout() <= 0) {
308
- Logger.warn(LiveUpdate.TAG, "Ready timeout is set to 0. Automatic rollback is disabled.");
289
+ Logger.warn(LiveUpdatePlugin.TAG, "Ready timeout is set to 0. Automatic rollback is disabled.");
309
290
  }
310
291
  // Stop the rollback timer
311
292
  stopRollbackTimer();
@@ -371,7 +352,7 @@ public class LiveUpdate {
371
352
  if (hasBundleById(bundleId)) {
372
353
  setNextBundleById(bundleId);
373
354
  } else {
374
- Exception exception = CustomExceptions.BUNDLE_NOT_FOUND;
355
+ Exception exception = new Exception(LiveUpdatePlugin.ERROR_BUNDLE_NOT_FOUND);
375
356
  callback.error(exception);
376
357
  return;
377
358
  }
@@ -381,7 +362,7 @@ public class LiveUpdate {
381
362
 
382
363
  public void sync(@NonNull SyncOptions options, @NonNull NonEmptyCallback<Result> callback) {
383
364
  if (syncInProgress) {
384
- Exception exception = CustomExceptions.SYNC_IN_PROGRESS;
365
+ Exception exception = new Exception(LiveUpdatePlugin.ERROR_SYNC_IN_PROGRESS);
385
366
  callback.error(exception);
386
367
  return;
387
368
  }
@@ -397,7 +378,7 @@ public class LiveUpdate {
397
378
  public void success(@Nullable GetLatestBundleResponse response) {
398
379
  try {
399
380
  if (response == null) {
400
- Logger.debug(LiveUpdate.TAG, "No update available.");
381
+ Logger.debug(LiveUpdatePlugin.TAG, "No update available.");
401
382
  syncInProgress = false;
402
383
  SyncResult syncResult = new SyncResult(null);
403
384
  callback.success(syncResult);
@@ -410,7 +391,7 @@ public class LiveUpdate {
410
391
  String url = response.getUrl();
411
392
  // Check if the bundle is blocked
412
393
  if (isBlockedBundleId(latestBundleId)) {
413
- Logger.warn(LiveUpdate.TAG, "Bundle is blocked and will not be downloaded.");
394
+ Logger.warn(LiveUpdatePlugin.TAG, "Bundle is blocked and will not be downloaded.");
414
395
  syncInProgress = false;
415
396
  SyncResult syncResult = new SyncResult(null);
416
397
  callback.success(syncResult);
@@ -478,7 +459,7 @@ public class LiveUpdate {
478
459
  // Search folder with index.html file
479
460
  File indexHtmlFile = searchIndexHtmlFile(sourceDirectory);
480
461
  if (indexHtmlFile == null) {
481
- throw CustomExceptions.BUNDLE_INDEX_HTML_MISSING;
462
+ throw new Exception(LiveUpdatePlugin.ERROR_BUNDLE_INDEX_HTML_MISSING);
482
463
  }
483
464
 
484
465
  // Create the bundles directory if it does not exist
@@ -501,21 +482,21 @@ public class LiveUpdate {
501
482
  }
502
483
 
503
484
  private File buildBundlesDirectory() {
504
- return new File(context.getFilesDir(), bundlesDirectory);
485
+ return new File(plugin.getContext().getFilesDir(), bundlesDirectory);
505
486
  }
506
487
 
507
488
  private File buildBundleDirectoryFor(@NonNull String bundleId) {
508
- return new File(context.getFilesDir(), bundlesDirectory + "/" + bundleId);
489
+ return new File(plugin.getContext().getFilesDir(), bundlesDirectory + "/" + bundleId);
509
490
  }
510
491
 
511
492
  private File buildTemporaryDirectory() {
512
493
  String fileName = UUID.randomUUID().toString();
513
- return new File(context.getCacheDir(), fileName);
494
+ return new File(plugin.getContext().getCacheDir(), fileName);
514
495
  }
515
496
 
516
497
  private File buildTemporaryZipFile() {
517
498
  String fileName = UUID.randomUUID().toString() + ".zip";
518
- return new File(context.getCacheDir(), fileName);
499
+ return new File(plugin.getContext().getCacheDir(), fileName);
519
500
  }
520
501
 
521
502
  private void copyCurrentBundleFile(@NonNull ManifestItem fileToCopy, @NonNull File destinationDirectory) throws IOException {
@@ -523,7 +504,7 @@ public class LiveUpdate {
523
504
  String currentBundleId = getCurrentBundleId();
524
505
  if (currentBundleId == null) {
525
506
  // Create the source input stream
526
- AssetManager assets = context.getAssets();
507
+ AssetManager assets = plugin.getContext().getAssets();
527
508
  InputStream inputStream = assets.open(defaultWebAssetDir + "/" + href);
528
509
  // Create the destination file
529
510
  File destination = new File(destinationDirectory, href);
@@ -551,7 +532,7 @@ public class LiveUpdate {
551
532
  for (ManifestItem fileToCopy : filesToCopy) {
552
533
  boolean success = tryCopyCurrentBundleFile(fileToCopy, destinationDirectory);
553
534
  if (!success) {
554
- Logger.warn(LiveUpdate.TAG, "Failed to copy file: " + fileToCopy.getHref());
535
+ Logger.warn(LiveUpdatePlugin.TAG, "Failed to copy file: " + fileToCopy.getHref());
555
536
  // If the file could not be copied, add it to the list of missing items
556
537
  missingItems.add(fileToCopy);
557
538
  }
@@ -597,8 +578,8 @@ public class LiveUpdate {
597
578
  KeyFactory keyFactory = KeyFactory.getInstance("RSA");
598
579
  return keyFactory.generatePublic(X509publicKey);
599
580
  } catch (Exception exception) {
600
- Logger.error(LiveUpdate.TAG, exception.getMessage(), exception);
601
- throw CustomExceptions.PUBLIC_KEY_INVALID;
581
+ Logger.error(LiveUpdatePlugin.TAG, exception.getMessage(), exception);
582
+ throw new Exception(LiveUpdatePlugin.ERROR_PUBLIC_KEY_INVALID);
602
583
  }
603
584
  }
604
585
 
@@ -664,8 +645,8 @@ public class LiveUpdate {
664
645
  completionCallback.success();
665
646
  } else {
666
647
  String errorMessage = response.body().string();
667
- Exception exception = CustomExceptions.DOWNLOAD_FAILED;
668
- Logger.error(LiveUpdate.TAG, errorMessage, exception);
648
+ Exception exception = new Exception(LiveUpdatePlugin.ERROR_DOWNLOAD_FAILED);
649
+ Logger.error(LiveUpdatePlugin.TAG, errorMessage, exception);
669
650
  completionCallback.error(exception);
670
651
  }
671
652
  } catch (Exception e) {
@@ -768,7 +749,7 @@ public class LiveUpdate {
768
749
  public void error(@NonNull Exception e) {
769
750
  // Capture first error and cancel all remaining downloads
770
751
  if (firstError.compareAndSet(null, e)) {
771
- Logger.error(LiveUpdate.TAG, "Failed to download file: " + item.getHref(), e);
752
+ Logger.error(LiveUpdatePlugin.TAG, "Failed to download file: " + item.getHref(), e);
772
753
  // Cancel all in-flight downloads (fail-fast)
773
754
  synchronized (activeCalls) {
774
755
  for (Call activeCall : activeCalls) {
@@ -943,10 +924,10 @@ public class LiveUpdate {
943
924
  .addQueryParameter("deviceId", getDeviceId())
944
925
  .addQueryParameter("osVersion", String.valueOf(Build.VERSION.SDK_INT))
945
926
  .addQueryParameter("platform", "0")
946
- .addQueryParameter("pluginVersion", LiveUpdate.VERSION)
927
+ .addQueryParameter("pluginVersion", LiveUpdatePlugin.VERSION)
947
928
  .build()
948
929
  .toString();
949
- Logger.debug(LiveUpdate.TAG, "Fetching latest bundle: " + url);
930
+ Logger.debug(LiveUpdatePlugin.TAG, "Fetching latest bundle: " + url);
950
931
 
951
932
  httpClient.enqueue(
952
933
  url,
@@ -955,7 +936,7 @@ public class LiveUpdate {
955
936
  public void success(@NonNull Response response) {
956
937
  try {
957
938
  String responseBodyString = response.body().string();
958
- Logger.debug(LiveUpdate.TAG, "Latest bundle response: " + responseBodyString);
939
+ Logger.debug(LiveUpdatePlugin.TAG, "Latest bundle response: " + responseBodyString);
959
940
  if (response.isSuccessful()) {
960
941
  JSONObject responseJson = new JSONObject(responseBodyString);
961
942
  GetLatestBundleResponse result = new GetLatestBundleResponse(responseJson);
@@ -1005,8 +986,8 @@ public class LiveUpdate {
1005
986
  source.close();
1006
987
  return digest.digest();
1007
988
  } catch (IOException exception) {
1008
- Logger.error(LiveUpdate.TAG, exception.getMessage(), exception);
1009
- throw CustomExceptions.CHECKSUM_CALCULATION_FAILED;
989
+ Logger.error(LiveUpdatePlugin.TAG, exception.getMessage(), exception);
990
+ throw new Exception(LiveUpdatePlugin.ERROR_CHECKSUM_CALCULATION_FAILED);
1010
991
  }
1011
992
  }
1012
993
 
@@ -1056,7 +1037,7 @@ public class LiveUpdate {
1056
1037
  * @return The absolute path to the current bundle directory (`public` for the built-in bundle).
1057
1038
  */
1058
1039
  private String getCurrentCapacitorServerPath() {
1059
- return bridge.getServerBasePath();
1040
+ return plugin.getBridge().getServerBasePath();
1060
1041
  }
1061
1042
 
1062
1043
  @NonNull
@@ -1086,7 +1067,8 @@ public class LiveUpdate {
1086
1067
  */
1087
1068
  @NonNull
1088
1069
  private String getNextCapacitorServerPath() {
1089
- String path = context
1070
+ String path = plugin
1071
+ .getContext()
1090
1072
  .getSharedPreferences(WebView.WEBVIEW_PREFS_NAME, Activity.MODE_PRIVATE)
1091
1073
  .getString(WebView.CAP_SERVER_PATH, defaultWebAssetDir);
1092
1074
  // Empty path means default path
@@ -1131,7 +1113,7 @@ public class LiveUpdate {
1131
1113
  private Manifest loadCurrentManifest() throws Exception {
1132
1114
  String currentBundleId = getCurrentBundleId();
1133
1115
  if (currentBundleId == null) {
1134
- AssetManager assets = context.getAssets();
1116
+ AssetManager assets = plugin.getContext().getAssets();
1135
1117
  boolean manifestFileExists = Arrays.asList(assets.list(defaultWebAssetDir)).contains(manifestFileName);
1136
1118
  if (manifestFileExists) {
1137
1119
  InputStream inputStream = assets.open(defaultWebAssetDir + "/" + manifestFileName);
@@ -1163,14 +1145,14 @@ public class LiveUpdate {
1163
1145
  }
1164
1146
 
1165
1147
  private void notifyDownloadBundleProgressListeners(@NonNull final DownloadBundleProgressEvent event) {
1166
- eventEmitter.onDownloadBundleProgress(event);
1148
+ plugin.notifyDownloadBundleProgressListeners(event);
1167
1149
  }
1168
1150
 
1169
1151
  private void performAutoUpdate() {
1170
1152
  // Check if enough time has passed since the last check
1171
1153
  long now = System.currentTimeMillis();
1172
1154
  if (lastAutoUpdateCheckTimestamp > 0 && (now - lastAutoUpdateCheckTimestamp) < autoUpdateIntervalMs) {
1173
- Logger.debug(LiveUpdate.TAG, "Auto-update skipped. Last check was less than 15 minutes ago.");
1155
+ Logger.debug(LiveUpdatePlugin.TAG, "Auto-update skipped. Last check was less than 15 minutes ago.");
1174
1156
  return;
1175
1157
  }
1176
1158
 
@@ -1178,17 +1160,17 @@ public class LiveUpdate {
1178
1160
  lastAutoUpdateCheckTimestamp = now;
1179
1161
 
1180
1162
  // Run sync
1181
- Logger.debug(LiveUpdate.TAG, "Auto-update started.");
1163
+ Logger.debug(LiveUpdatePlugin.TAG, "Auto-update started.");
1182
1164
  SyncOptions options = new SyncOptions((String) null);
1183
1165
  NonEmptyCallback<Result> callback = new NonEmptyCallback<>() {
1184
1166
  @Override
1185
1167
  public void success(@NonNull Result result) {
1186
- Logger.debug(LiveUpdate.TAG, "Auto-update completed successfully.");
1168
+ Logger.debug(LiveUpdatePlugin.TAG, "Auto-update completed successfully.");
1187
1169
  }
1188
1170
 
1189
1171
  @Override
1190
1172
  public void error(@NonNull Exception exception) {
1191
- Logger.error(LiveUpdate.TAG, "Auto-update failed: " + exception.getMessage(), exception);
1173
+ Logger.error(LiveUpdatePlugin.TAG, "Auto-update failed: " + exception.getMessage(), exception);
1192
1174
  }
1193
1175
  };
1194
1176
  sync(options, callback);
@@ -1202,9 +1184,9 @@ public class LiveUpdate {
1202
1184
  setPreviousBundleId(currentBundleId);
1203
1185
  // Log the rollback result
1204
1186
  if (currentBundleId == null) {
1205
- Logger.debug(LiveUpdate.TAG, "App is not ready. Default bundle is already in use.");
1187
+ Logger.debug(LiveUpdatePlugin.TAG, "App is not ready. Default bundle is already in use.");
1206
1188
  } else {
1207
- Logger.debug(LiveUpdate.TAG, "App is not ready. Rolling back to default bundle.");
1189
+ Logger.debug(LiveUpdatePlugin.TAG, "App is not ready. Rolling back to default bundle.");
1208
1190
  // Rollback to the default bundle
1209
1191
  setNextBundleById(null);
1210
1192
  setCurrentBundleById(null);
@@ -1250,11 +1232,11 @@ public class LiveUpdate {
1250
1232
 
1251
1233
  private void setCurrentCapacitorServerPath(@NonNull String path) {
1252
1234
  if (path.equals(defaultWebAssetDir)) {
1253
- this.bridge.setServerAssetPath(path);
1235
+ this.plugin.getBridge().setServerAssetPath(path);
1254
1236
  } else {
1255
- this.bridge.setServerBasePath(path);
1237
+ this.plugin.getBridge().setServerBasePath(path);
1256
1238
  }
1257
- this.bridge.reload();
1239
+ this.plugin.getBridge().reload();
1258
1240
  // Notify listeners
1259
1241
  notifyReloadedListeners();
1260
1242
  }
@@ -1276,11 +1258,11 @@ public class LiveUpdate {
1276
1258
 
1277
1259
  private void notifyNextBundleSetListeners(@Nullable String bundleId) {
1278
1260
  NextBundleSetEvent event = new NextBundleSetEvent(bundleId);
1279
- eventEmitter.onNextBundleSet(event);
1261
+ plugin.notifyNextBundleSetListeners(event);
1280
1262
  }
1281
1263
 
1282
1264
  private void notifyReloadedListeners() {
1283
- eventEmitter.onReloaded();
1265
+ plugin.notifyReloadedListeners();
1284
1266
  }
1285
1267
 
1286
1268
  private void addBlockedBundleId(@NonNull String bundleId) {
@@ -1310,7 +1292,7 @@ public class LiveUpdate {
1310
1292
  String newBlockedIds = String.join(",", blockedList);
1311
1293
  preferences.setBlockedBundleIds(newBlockedIds);
1312
1294
 
1313
- Logger.debug(LiveUpdate.TAG, "Bundle blocked: " + bundleId);
1295
+ Logger.debug(LiveUpdatePlugin.TAG, "Bundle blocked: " + bundleId);
1314
1296
  }
1315
1297
 
1316
1298
  private boolean isBlockedBundleId(@NonNull String bundleId) {
@@ -1334,7 +1316,7 @@ public class LiveUpdate {
1334
1316
 
1335
1317
  if (lastVersionCode == -1 || lastVersionCode != currentVersionCode) {
1336
1318
  Logger.debug(
1337
- LiveUpdate.TAG,
1319
+ LiveUpdatePlugin.TAG,
1338
1320
  "App version changed (last: " + lastVersionCode + ", current: " + currentVersionCode + "), resetting config."
1339
1321
  );
1340
1322
  resetConfig();
@@ -1384,12 +1366,12 @@ public class LiveUpdate {
1384
1366
  if (publicKey != null) {
1385
1367
  // Verify the signature
1386
1368
  if (signature == null) {
1387
- throw CustomExceptions.SIGNATURE_MISSING;
1369
+ throw new Exception(LiveUpdatePlugin.ERROR_SIGNATURE_MISSING);
1388
1370
  }
1389
1371
  // Verify the signature
1390
1372
  boolean verified = verifySignatureForFile(file, signature, publicKey);
1391
1373
  if (!verified) {
1392
- throw CustomExceptions.SIGNATURE_VERIFICATION_FAILED;
1374
+ throw new Exception(LiveUpdatePlugin.ERROR_SIGNATURE_VERIFICATION_FAILED);
1393
1375
  }
1394
1376
  }
1395
1377
  // Verify the checksum
@@ -1397,7 +1379,7 @@ public class LiveUpdate {
1397
1379
  // Calculate the checksum
1398
1380
  boolean verified = verifyChecksumForFile(file, checksum);
1399
1381
  if (!verified) {
1400
- throw CustomExceptions.CHECKSUM_MISMATCH;
1382
+ throw new Exception(LiveUpdatePlugin.ERROR_CHECKSUM_MISMATCH);
1401
1383
  }
1402
1384
  }
1403
1385
  }
@@ -1420,17 +1402,17 @@ public class LiveUpdate {
1420
1402
  source.close();
1421
1403
  return sig.verify(signatureBytes);
1422
1404
  } catch (Exception exception) {
1423
- Logger.error(LiveUpdate.TAG, exception.getMessage(), exception);
1424
- throw CustomExceptions.SIGNATURE_VERIFICATION_FAILED;
1405
+ Logger.error(LiveUpdatePlugin.TAG, exception.getMessage(), exception);
1406
+ throw new Exception(LiveUpdatePlugin.ERROR_SIGNATURE_VERIFICATION_FAILED);
1425
1407
  }
1426
1408
  }
1427
1409
 
1428
1410
  private PackageInfo getPackageInfo() throws PackageManager.NameNotFoundException {
1429
- String packageName = this.context.getPackageName();
1411
+ String packageName = this.plugin.getContext().getPackageName();
1430
1412
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
1431
- return this.context.getPackageManager().getPackageInfo(packageName, PackageManager.PackageInfoFlags.of(0));
1413
+ return this.plugin.getContext().getPackageManager().getPackageInfo(packageName, PackageManager.PackageInfoFlags.of(0));
1432
1414
  } else {
1433
- return this.context.getPackageManager().getPackageInfo(packageName, 0);
1415
+ return this.plugin.getContext().getPackageManager().getPackageInfo(packageName, 0);
1434
1416
  }
1435
1417
  }
1436
1418
  }
@@ -28,15 +28,15 @@ import io.capawesome.capacitorjs.plugins.liveupdate.classes.results.GetDownloade
28
28
  import io.capawesome.capacitorjs.plugins.liveupdate.classes.results.GetNextBundleResult;
29
29
  import io.capawesome.capacitorjs.plugins.liveupdate.classes.results.IsSyncingResult;
30
30
  import io.capawesome.capacitorjs.plugins.liveupdate.interfaces.EmptyCallback;
31
- import io.capawesome.capacitorjs.plugins.liveupdate.interfaces.LiveUpdateEventEmitter;
32
31
  import io.capawesome.capacitorjs.plugins.liveupdate.interfaces.NonEmptyCallback;
33
32
  import io.capawesome.capacitorjs.plugins.liveupdate.interfaces.Result;
34
33
 
35
34
  @CapacitorPlugin(name = "LiveUpdate")
36
35
  public class LiveUpdatePlugin extends Plugin {
37
36
 
38
- public static final String TAG = LiveUpdate.TAG;
39
- public static final String VERSION = LiveUpdate.VERSION;
37
+ public static final String TAG = "LiveUpdate";
38
+ public static final String VERSION = "8.1.0";
39
+ public static final String SHARED_PREFERENCES_NAME = "CapawesomeLiveUpdate"; // DO NOT CHANGE
40
40
  public static final String ERROR_APP_ID_MISSING = "appId must be configured.";
41
41
  public static final String ERROR_BUNDLE_EXISTS = "bundle already exists.";
42
42
  public static final String ERROR_BUNDLE_ID_MISSING = "bundleId must be provided.";
@@ -68,8 +68,7 @@ public class LiveUpdatePlugin extends Plugin {
68
68
  public void load() {
69
69
  try {
70
70
  config = getLiveUpdateConfig();
71
- LiveUpdateEventEmitter eventEmitter = new PluginLiveUpdateEventEmitter();
72
- implementation = new LiveUpdate(getContext(), getBridge(), config, eventEmitter);
71
+ implementation = new LiveUpdate(config, this);
73
72
  } catch (Exception exception) {
74
73
  Logger.error(TAG, exception.getMessage(), exception);
75
74
  }
@@ -685,22 +684,4 @@ public class LiveUpdatePlugin extends Plugin {
685
684
  Logger.error(TAG, message, exception);
686
685
  call.reject(message);
687
686
  }
688
-
689
- private class PluginLiveUpdateEventEmitter implements LiveUpdateEventEmitter {
690
-
691
- @Override
692
- public void onDownloadBundleProgress(@NonNull DownloadBundleProgressEvent event) {
693
- notifyDownloadBundleProgressListeners(event);
694
- }
695
-
696
- @Override
697
- public void onNextBundleSet(@NonNull NextBundleSetEvent event) {
698
- notifyNextBundleSetListeners(event);
699
- }
700
-
701
- @Override
702
- public void onReloaded() {
703
- notifyReloadedListeners();
704
- }
705
- }
706
687
  }
@@ -9,8 +9,6 @@ import java.util.UUID;
9
9
 
10
10
  public class LiveUpdatePreferences {
11
11
 
12
- private static final String SHARED_PREFERENCES_NAME = "CapawesomeLiveUpdate"; // DO NOT CHANGE
13
-
14
12
  @NonNull
15
13
  private final Context context;
16
14
 
@@ -27,45 +25,53 @@ public class LiveUpdatePreferences {
27
25
 
28
26
  public LiveUpdatePreferences(@NonNull Context context) {
29
27
  this.context = context;
30
- this.settingsEditor = context.getSharedPreferences(SHARED_PREFERENCES_NAME, Activity.MODE_PRIVATE).edit();
28
+ this.settingsEditor = context.getSharedPreferences(LiveUpdatePlugin.SHARED_PREFERENCES_NAME, Activity.MODE_PRIVATE).edit();
31
29
  }
32
30
 
33
31
  @Nullable
34
32
  public String getAppId() {
35
- return context.getSharedPreferences(SHARED_PREFERENCES_NAME, Activity.MODE_PRIVATE).getString(appIdKey, null);
33
+ return context.getSharedPreferences(LiveUpdatePlugin.SHARED_PREFERENCES_NAME, Activity.MODE_PRIVATE).getString(appIdKey, null);
36
34
  }
37
35
 
38
36
  @Nullable
39
37
  public String getChannel() {
40
- return context.getSharedPreferences(SHARED_PREFERENCES_NAME, Activity.MODE_PRIVATE).getString(channelKey, null);
38
+ return context.getSharedPreferences(LiveUpdatePlugin.SHARED_PREFERENCES_NAME, Activity.MODE_PRIVATE).getString(channelKey, null);
41
39
  }
42
40
 
43
41
  @Nullable
44
42
  public String getCustomId() {
45
- return context.getSharedPreferences(SHARED_PREFERENCES_NAME, Activity.MODE_PRIVATE).getString(customIdKey, null);
43
+ return context.getSharedPreferences(LiveUpdatePlugin.SHARED_PREFERENCES_NAME, Activity.MODE_PRIVATE).getString(customIdKey, null);
46
44
  }
47
45
 
48
46
  @Nullable
49
47
  public String getDeviceIdForApp(@Nullable String appId) {
50
48
  if (appId == null) {
51
- return context.getSharedPreferences(SHARED_PREFERENCES_NAME, Activity.MODE_PRIVATE).getString(deviceIdKey, null);
49
+ return context
50
+ .getSharedPreferences(LiveUpdatePlugin.SHARED_PREFERENCES_NAME, Activity.MODE_PRIVATE)
51
+ .getString(deviceIdKey, null);
52
52
  } else {
53
- return context.getSharedPreferences(SHARED_PREFERENCES_NAME, Activity.MODE_PRIVATE).getString(deviceIdKey + "_" + appId, null);
53
+ return context
54
+ .getSharedPreferences(LiveUpdatePlugin.SHARED_PREFERENCES_NAME, Activity.MODE_PRIVATE)
55
+ .getString(deviceIdKey + "_" + appId, null);
54
56
  }
55
57
  }
56
58
 
57
59
  public int getLastVersionCode() {
58
- return context.getSharedPreferences(SHARED_PREFERENCES_NAME, Activity.MODE_PRIVATE).getInt(lastVersionCodeKey, -1);
60
+ return context.getSharedPreferences(LiveUpdatePlugin.SHARED_PREFERENCES_NAME, Activity.MODE_PRIVATE).getInt(lastVersionCodeKey, -1);
59
61
  }
60
62
 
61
63
  @Nullable
62
64
  public String getPreviousBundleId() {
63
- return context.getSharedPreferences(SHARED_PREFERENCES_NAME, Activity.MODE_PRIVATE).getString(previousBundleIdKey, null);
65
+ return context
66
+ .getSharedPreferences(LiveUpdatePlugin.SHARED_PREFERENCES_NAME, Activity.MODE_PRIVATE)
67
+ .getString(previousBundleIdKey, null);
64
68
  }
65
69
 
66
70
  @Nullable
67
71
  public String getBlockedBundleIds() {
68
- return context.getSharedPreferences(SHARED_PREFERENCES_NAME, Activity.MODE_PRIVATE).getString(blockedBundleIdsKey, null);
72
+ return context
73
+ .getSharedPreferences(LiveUpdatePlugin.SHARED_PREFERENCES_NAME, Activity.MODE_PRIVATE)
74
+ .getString(blockedBundleIdsKey, null);
69
75
  }
70
76
 
71
77
  public void setAppId(@Nullable String appId) {
package/dist/docs.json CHANGED
@@ -663,7 +663,7 @@
663
663
  "name": "since"
664
664
  }
665
665
  ],
666
- "docs": "The checksum of the self-hosted bundle as a SHA-256 hash\nin base64 format to verify the integrity of the bundle.\n\n**Attention**: Only supported for the `zip` artifact type.",
666
+ "docs": "The checksum of the self-hosted bundle as a SHA-256 hash\nin hex format to verify the integrity of the bundle.\n\n**Attention**: Only supported for the `zip` artifact type.",
667
667
  "complexTypes": [],
668
668
  "type": "string | undefined"
669
669
  },
@@ -691,7 +691,7 @@
691
691
  "name": "example"
692
692
  }
693
693
  ],
694
- "docs": "The URL of the bundle to download.\n\nFor the `zip` artifact type, the URL must point to a ZIP file.\nFor the `manifest` artifact type, the URL serves as the base URL\nto download the individual files. For example, if the URL is\n`https://example.com/download`, the plugin will download the file\nwith the href `index.html` from `https://example.com/download?href=index.html`.\n\nTo **verify the integrity** of the file, the server should return\na `X-Checksum` header with the SHA-256 hash in base64 format.\n\nTo **verify the signature** of the file, the server should return\na `X-Signature` header with the signed SHA-256 hash in base64 format.",
694
+ "docs": "The URL of the bundle to download.\n\nFor the `zip` artifact type, the URL must point to a ZIP file.\nFor the `manifest` artifact type, the URL serves as the base URL\nto download the individual files. For example, if the URL is\n`https://example.com/download`, the plugin will download the file\nwith the href `index.html` from `https://example.com/download?href=index.html`.\n\nTo **verify the integrity** of the file, the server should return\na `X-Checksum` header with the SHA-256 hash in hex format.\n\nTo **verify the signature** of the file, the server should return\na `X-Signature` header with the signed SHA-256 hash in base64 format.",
695
695
  "complexTypes": [],
696
696
  "type": "string"
697
697
  }
@@ -413,7 +413,7 @@ export interface DownloadBundleOptions {
413
413
  bundleId: string;
414
414
  /**
415
415
  * The checksum of the self-hosted bundle as a SHA-256 hash
416
- * in base64 format to verify the integrity of the bundle.
416
+ * in hex format to verify the integrity of the bundle.
417
417
  *
418
418
  * **Attention**: Only supported for the `zip` artifact type.
419
419
  *
@@ -439,7 +439,7 @@ export interface DownloadBundleOptions {
439
439
  * with the href `index.html` from `https://example.com/download?href=index.html`.
440
440
  *
441
441
  * To **verify the integrity** of the file, the server should return
442
- * a `X-Checksum` header with the SHA-256 hash in base64 format.
442
+ * a `X-Checksum` header with the SHA-256 hash in hex format.
443
443
  *
444
444
  * To **verify the signature** of the file, the server should return
445
445
  * a `X-Signature` header with the signed SHA-256 hash in base64 format.
@@ -1 +1 @@
1
- {"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"AAAA,wCAAwC","sourcesContent":["/// <reference types=\"@capacitor/cli\" />\n\nimport type { PluginListenerHandle } from '@capacitor/core';\n\ndeclare module '@capacitor/cli' {\n export interface PluginsConfig {\n LiveUpdate?: {\n /**\n * The app ID is used to identify the app when using [Capawesome Cloud](https://capawesome.io/cloud/).\n *\n * This is **NOT** the same as the app identifier (e.g. `com.example.app`).\n * This is a unique identifier generated by Capawesome Cloud (e.g. `6e351b4f-69a7-415e-a057-4567df7ffe94`).\n *\n * @since 5.0.0\n * @example '6e351b4f-69a7-415e-a057-4567df7ffe94'\n */\n appId?: string;\n /**\n * Whether or not to automatically block bundles that have been rolled back.\n *\n * When enabled, the plugin will automatically block bundles that caused a rollback\n * (up to 100 bundles). When the limit is reached, the oldest blocked bundle is unblocked.\n * Blocked bundles will be skipped in future sync operations.\n *\n * **Attention**: This option has no effect if `readyTimeout` is set to `0`.\n *\n * Only available on Android and iOS.\n *\n * @since 7.3.0\n * @default false\n */\n autoBlockRolledBackBundles?: boolean;\n /**\n * Whether or not to automatically delete unused bundles.\n *\n * When enabled, the plugin will automatically delete unused bundles after calling `ready()`.\n *\n * @since 5.0.0\n * @default false\n */\n autoDeleteBundles?: boolean;\n /**\n * The auto-update strategy for live updates.\n *\n * - `none`: Live updates will not be applied automatically.\n * - `background`: Live updates will be automatically downloaded\n * and applied in the background at app startup and when the app resumes\n * (if the last check was more than 15 minutes ago).\n *\n * Only available on Android and iOS.\n *\n * @since 7.3.0\n * @default 'none'\n * @example 'background'\n */\n autoUpdateStrategy?: 'none' | 'background';\n /**\n * The default channel of the app.\n *\n * @since 6.3.0\n * @example 'production'\n */\n defaultChannel?: string;\n /**\n * The timeout in milliseconds for HTTP requests.\n *\n * @since 6.4.0\n * @default 60000\n */\n httpTimeout?: number;\n /**\n * The public key to verify the integrity of the bundle.\n *\n * The public key must be a PEM-encoded RSA public key.\n *\n * @since 6.1.0\n * @example '-----BEGIN PUBLIC KEY-----MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDDodf1SD0OOn6hIlDuKBza0Ed0OqtwyVJwiyjmE9BJaZ7y8ZUfcF+SKmd0l2cDPM45XIg2tAFux5n29uoKyHwSt+6tCi5CJA5Z1/1eZruRRqABLonV77KS3HUtvOgqRLDnKSV89dYZkM++NwmzOPgIF422mvc+VukcVOBfc8/AHQIDAQAB-----END PUBLIC KEY-----'\n */\n publicKey?: string;\n /**\n * The timeout in milliseconds to wait for the app to be ready\n * before resetting to the default bundle.\n *\n * It is strongly **recommended** to configure this option (e.g. `10000` ms)\n * so that the plugin can roll back to the default bundle in case of problems.\n * If configured, the plugin will wait for the app to call the `ready()`\n * method before resetting to the default bundle.\n *\n * Set to `0` to disable the timeout.\n *\n * @since 5.0.0\n * @default 0\n * @example 10000\n */\n readyTimeout?: number;\n /**\n * The API domain of the [Capawesome Cloud](https://cloud.capawesome.io) server **without** scheme or path.\n *\n * @since 7.0.0\n * @default 'api.cloud.capawesome.io'\n * @example 'api.cloud.capawesome.eu'\n */\n serverDomain?: string;\n };\n }\n}\n\nexport interface LiveUpdatePlugin {\n /**\n * Clear all blocked bundles from the blocked list.\n *\n * This removes all bundle identifiers that were automatically blocked\n * due to rollbacks when `autoBlockRolledBackBundles` is enabled.\n *\n * Only available on Android and iOS.\n *\n * @since 7.4.0\n */\n clearBlockedBundles(): Promise<void>;\n /**\n * Delete a bundle from the app.\n *\n * Only available on Android and iOS.\n *\n * @since 5.0.0\n */\n deleteBundle(options: DeleteBundleOptions): Promise<void>;\n /**\n * Download a bundle.\n *\n * Only available on Android and iOS.\n *\n * @since 5.0.0\n */\n downloadBundle(options: DownloadBundleOptions): Promise<void>;\n /**\n * Fetch the latest bundle using the [Capawesome Cloud](https://capawesome.io/cloud/).\n *\n * Only available on Android and iOS.\n *\n * @since 6.6.0\n */\n fetchLatestBundle(\n options?: FetchLatestBundleOptions,\n ): Promise<FetchLatestBundleResult>;\n /**\n * Get all blocked bundle identifiers.\n *\n * Returns the list of bundle identifiers that were automatically blocked\n * due to rollbacks when `autoBlockRolledBackBundles` is enabled.\n *\n * Only available on Android and iOS.\n *\n * @since 7.4.0\n */\n getBlockedBundles(): Promise<GetBlockedBundlesResult>;\n /**\n * Get all identifiers of bundles that have been downloaded.\n *\n * Only available on Android and iOS.\n *\n * @since 5.0.0\n * @deprecated Use `getDownloadedBundles()` instead.\n */\n getBundles(): Promise<GetBundlesResult>;\n /**\n * Get the channel that is used for the update.\n *\n * Only available on Android and iOS.\n *\n * @since 5.0.0\n */\n getChannel(): Promise<GetChannelResult>;\n /**\n * Get the runtime configuration.\n *\n * Returns the current plugin configuration including any runtime\n * overrides set via `setConfig()`.\n *\n * Only available on Android and iOS.\n *\n * @since 7.4.0\n */\n getConfig(): Promise<GetConfigResult>;\n /**\n * Get all identifiers of bundles that have been downloaded.\n *\n * Only available on Android and iOS.\n *\n * @since 7.4.0\n */\n getDownloadedBundles(): Promise<GetDownloadedBundlesResult>;\n /**\n * Get the bundle identifier of the current bundle.\n * The current bundle is the bundle that is currently used by the app.\n *\n * Only available on Android and iOS.\n *\n * @since 6.7.0\n */\n getCurrentBundle(): Promise<GetCurrentBundleResult>;\n /**\n * Get the custom identifier of the device.\n *\n * Only available on Android and iOS.\n *\n * @since 5.0.0\n */\n getCustomId(): Promise<GetCustomIdResult>;\n /**\n * Get the unique device identifier.\n *\n * Only available on Android and iOS.\n *\n * @since 5.0.0\n */\n getDeviceId(): Promise<GetDeviceIdResult>;\n /**\n * Check whether a sync operation is currently in progress.\n *\n * Only available on Android and iOS.\n *\n * @since 7.4.0\n */\n isSyncing(): Promise<IsSyncingResult>;\n /**\n * Get the bundle identifier of the next bundle.\n * The next bundle is the bundle that will be used after calling `reload()`\n * or restarting the app.\n *\n * Only available on Android and iOS.\n *\n * @since 6.7.0\n */\n getNextBundle(): Promise<GetNextBundleResult>;\n /**\n * Get the version code of the app.\n *\n * On **Android**, this is the `versionCode` from the `android/app/build.gradle` file.\n * On **iOS**, this is the `CFBundleVersion` from the `Info.plist` file.\n *\n * Only available on Android and iOS.\n *\n * @since 5.0.0\n */\n getVersionCode(): Promise<GetVersionCodeResult>;\n /**\n * Get the version name of the app.\n *\n * On **Android**, this is the `versionName` from the `android/app/build.gradle` file.\n * On **iOS**, this is the `CFBundleShortVersionString` from the `Info.plist` file.\n *\n * Only available on Android and iOS.\n *\n * @since 5.0.0\n */\n getVersionName(): Promise<GetVersionNameResult>;\n /**\n * Notify the plugin that the app is ready to use and no rollback is needed.\n *\n * **Attention**: This method should be called as soon as the app is ready to use\n * to prevent the app from being reset to the default bundle.\n *\n * Only available on Android and iOS.\n *\n * @since 5.0.0\n */\n ready(): Promise<ReadyResult>;\n /**\n * Reload the app to apply the new bundle.\n *\n * Only available on Android and iOS.\n *\n * @since 5.0.0\n */\n reload(): Promise<void>;\n /**\n * Reset the app to the default bundle.\n *\n * Call `reload()` or restart the app to apply the changes.\n *\n * Only available on Android and iOS.\n *\n * @since 5.0.0\n */\n reset(): Promise<void>;\n /**\n * Reset the runtime configuration to the values from the Capacitor config file.\n *\n * This clears any runtime configuration set via `setConfig()`.\n * The changes take effect immediately.\n *\n * Only available on Android and iOS.\n *\n * @since 7.4.0\n */\n resetConfig(): Promise<void>;\n /**\n * Set the channel to use for the update.\n *\n * Only available on Android and iOS.\n *\n * @since 5.0.0\n */\n setChannel(options: SetChannelOptions): Promise<void>;\n /**\n * Set the runtime configuration.\n *\n * This allows updating plugin configuration options at runtime.\n * The changes are persisted across app restarts and take effect immediately.\n *\n * **Important:** Runtime configuration is automatically reset to default values\n * whenever the native app is updated to a new version. This ensures that\n * configuration from previous versions doesn't persist after an app update.\n *\n * Only available on Android and iOS.\n *\n * @since 7.4.0\n */\n setConfig(options: SetConfigOptions): Promise<void>;\n /**\n * Set the custom identifier of the device.\n *\n * Only available on Android and iOS.\n *\n * @since 5.0.0\n */\n setCustomId(options: SetCustomIdOptions): Promise<void>;\n /**\n * Set the next bundle to use for the app.\n *\n * Call `reload()` or restart the app to apply the changes.\n *\n * Only available on Android and iOS.\n *\n * @since 6.7.0\n */\n setNextBundle(options: SetNextBundleOptions): Promise<void>;\n /**\n * Automatically download and set the latest bundle for the app using the [Capawesome Cloud](https://capawesome.io/cloud/).\n *\n * Call `reload()` or restart the app to apply the changes.\n *\n * Only available on Android and iOS.\n *\n * @since 5.0.0\n */\n sync(options?: SyncOptions): Promise<SyncResult>;\n /**\n * Listen for the download progress of a bundle.\n *\n * Only available on Android and iOS.\n *\n * @since 7.0.0\n */\n addListener(\n eventName: 'downloadBundleProgress',\n listenerFunc: DownloadBundleProgressListener,\n ): Promise<PluginListenerHandle>;\n /**\n * Listen for when a bundle is set as the next bundle.\n *\n * This event is triggered whenever a bundle is set to be used on the next app restart,\n * either through automatic updates or manual calls to `setNextBundle()`.\n *\n * Only available on Android and iOS.\n *\n * @since 7.3.0\n */\n addListener(\n eventName: 'nextBundleSet',\n listenerFunc: NextBundleSetListener,\n ): Promise<PluginListenerHandle>;\n /**\n * Listen for when the app is reloaded.\n *\n * This event is triggered after the `reload()` method is called\n * and the app has been reloaded.\n *\n * **Note:** To verify whether an update was successfully applied after a reload,\n * use the `ready()` method instead. The `ready()` method provides detailed information\n * about the current bundle, previous bundle, and whether a rollback occurred.\n *\n * Only available on Android and iOS.\n *\n * @since 7.4.0\n */\n addListener(\n eventName: 'reloaded',\n listenerFunc: ReloadedListener,\n ): Promise<PluginListenerHandle>;\n /**\n * Remove all listeners for this plugin.\n *\n * @since 7.2.0\n */\n removeAllListeners(): Promise<void>;\n}\n\n/**\n * @since 5.0.0\n */\nexport interface DeleteBundleOptions {\n /**\n * The unique identifier of the bundle to delete.\n *\n * @since 5.0.0\n * @example '1.0.0'\n */\n bundleId: string;\n}\n\nexport interface DownloadBundleOptions {\n /**\n * The artifact type of the bundle.\n *\n * @since 6.6.0\n * @default 'zip'\n * @example 'manifest'\n */\n artifactType?: 'manifest' | 'zip';\n /**\n * The unique identifier of the bundle.\n *\n * **Attention**: The value `public` is reserved and cannot be used as a bundle identifier.\n *\n * @since 5.0.0\n * @example '1.0.0'\n */\n bundleId: string;\n /**\n * The checksum of the self-hosted bundle as a SHA-256 hash\n * in base64 format to verify the integrity of the bundle.\n *\n * **Attention**: Only supported for the `zip` artifact type.\n *\n * @since 7.1.0\n */\n checksum?: string;\n /**\n * The signature of the self-hosted bundle as a signed SHA-256 hash\n * in base64 format to verify the integrity of the bundle.\n *\n * **Attention**: Only supported for the `zip` artifact type.\n *\n * @since 7.1.0\n */\n signature?: string;\n /**\n * The URL of the bundle to download.\n *\n * For the `zip` artifact type, the URL must point to a ZIP file.\n * For the `manifest` artifact type, the URL serves as the base URL\n * to download the individual files. For example, if the URL is\n * `https://example.com/download`, the plugin will download the file\n * with the href `index.html` from `https://example.com/download?href=index.html`.\n *\n * To **verify the integrity** of the file, the server should return\n * a `X-Checksum` header with the SHA-256 hash in base64 format.\n *\n * To **verify the signature** of the file, the server should return\n * a `X-Signature` header with the signed SHA-256 hash in base64 format.\n *\n * @since 5.0.0\n * @example 'https://example.com/bundle.zip'\n */\n url: string;\n}\n\n/**\n * @since 6.7.0\n */\nexport interface FetchLatestBundleOptions {\n /**\n * The name of the channel where the latest bundle is fetched from.\n *\n * @since 6.7.0\n */\n channel?: string;\n}\n\n/**\n * @since 6.6.0\n */\nexport interface FetchLatestBundleResult {\n /**\n * The artifact type of the bundle.\n *\n * @since 6.7.0\n */\n artifactType?: 'manifest' | 'zip';\n /**\n * The unique identifier of the latest bundle.\n *\n * If `null`, no bundle is available.\n *\n * @since 6.6.0\n */\n bundleId: string | null;\n /**\n * The checksum of the latest bundle if the bundle is self-hosted.\n *\n * If the bundle is hosted on Capawesome Cloud, the checksum will be\n * returned as response header when downloading the bundle.\n *\n * @since 7.1.0\n */\n checksum?: string;\n /**\n * Custom properties that are associated with the latest bundle.\n *\n * @since 7.0.0\n * @example { \"key\": \"value\" }\n */\n customProperties?: { [key: string]: string };\n /**\n * The URL of the latest bundle to download.\n * Pass this URL to the `downloadBundle(...)` method to download the bundle.\n *\n * @since 6.7.0\n */\n downloadUrl?: string;\n /**\n * The signature of the latest bundle if the bundle is self-hosted.\n *\n * If the bundle is hosted on Capawesome Cloud, the signature will be\n * returned as response header when downloading the bundle.\n *\n * @since 7.1.0\n */\n signature?: string;\n}\n\n/**\n * @since 5.0.0\n */\nexport interface GetBundleResult {\n /**\n * The unique identifier of the active bundle.\n *\n * If `null`, the default bundle is being used.\n *\n * @since 5.0.0\n * @example '1.0.0'\n */\n bundleId: string | null;\n}\n\n/**\n * @since 7.4.0\n */\nexport interface GetBlockedBundlesResult {\n /**\n * An array of unique identifiers of all blocked bundles.\n *\n * @since 7.4.0\n */\n bundleIds: string[];\n}\n\n/**\n * @since 5.0.0\n */\nexport interface GetBundlesResult {\n /**\n * An array of unique identifiers of all available bundles.\n *\n * @since 5.0.0\n */\n bundleIds: string[];\n}\n\n/**\n * @since 7.4.0\n */\nexport interface GetDownloadedBundlesResult {\n /**\n * An array of unique identifiers of all downloaded bundles.\n *\n * @since 7.4.0\n */\n bundleIds: string[];\n}\n\n/**\n * @since 5.0.0\n */\nexport interface GetChannelResult {\n /**\n * The channel name.\n *\n * If `null`, the app is using the default channel.\n *\n * @since 5.0.0\n * @example 'production'\n */\n channel: string | null;\n}\n\n/**\n * @since 7.4.0\n */\nexport interface GetConfigResult {\n /**\n * The app ID used to identify the app.\n *\n * If `null`, no app ID is configured.\n *\n * @since 7.4.0\n * @example '6e351b4f-69a7-415e-a057-4567df7ffe94'\n */\n appId: string | null;\n /**\n * The auto-update strategy for live updates.\n *\n * @since 7.4.0\n * @example 'background'\n */\n autoUpdateStrategy: 'none' | 'background';\n}\n\n/**\n * @since 6.7.0\n */\nexport interface GetCurrentBundleResult {\n /**\n * The unique identifier of the current bundle.\n *\n * If `null`, the default bundle is being used.\n *\n * @since 6.7.0\n */\n bundleId: string | null;\n}\n\n/**\n * @since 5.0.0\n */\nexport interface GetDeviceIdResult {\n /**\n * The unique identifier of the device.\n *\n * On iOS, [`identifierForVendor`](https://developer.apple.com/documentation/uikit/uidevice/1620059-identifierforvendor) is used.\n * The value of this property is the same for apps that come from the same vendor running on the same device.\n *\n * @since 5.0.0\n *\n * @example '50d2a548-80b7-4dad-adc7-97c0e79d8a89'\n */\n deviceId: string;\n}\n\n/**\n * @since 7.4.0\n */\nexport interface IsSyncingResult {\n /**\n * Whether a sync operation is currently in progress.\n *\n * @since 7.4.0\n */\n syncing: boolean;\n}\n\n/**\n * @since 6.7.0\n */\nexport interface GetNextBundleResult {\n /**\n * The unique identifier of the next bundle.\n *\n * If `null`, the default bundle is being used.\n *\n * @since 6.7.0\n */\n bundleId: string | null;\n}\n\n/**\n * @since 5.0.0\n */\nexport interface GetVersionCodeResult {\n /**\n * The version code of the app.\n *\n * On **Android**, this is the `versionCode` from the `android/app/build.gradle` file.\n * On **iOS**, this is the `CFBundleVersion` from the `Info.plist` file.\n *\n * @since 5.0.0\n * @example \"1\"\n */\n versionCode: string;\n}\n\n/**\n * @since 5.0.0\n */\nexport interface GetVersionNameResult {\n /**\n * The version name of the app.\n *\n * On **Android**, this is the `versionName` from the `android/app/build.gradle` file.\n * On **iOS**, this is the `CFBundleShortVersionString` from the `Info.plist` file.\n *\n * @since 5.0.0\n * @example \"1.0.0\"\n */\n versionName: string;\n}\n\n/**\n * @since 5.0.0\n */\nexport interface GetCustomIdResult {\n /**\n * The custom identifier of the device.\n *\n * If `null`, no custom identifier is set.\n *\n * @since 5.0.0\n * @example '50d2a548-80b7-4dad-adc7-97c0e79d8a89'\n */\n customId: string | null;\n}\n\n/**\n * @since 7.0.0\n */\nexport interface ReadyResult {\n /**\n * The identifier of the previous bundle used.\n *\n * If `null`, the default bundle was used.\n *\n * @since 7.0.0\n */\n previousBundleId: string | null;\n /**\n * The identifier of the current bundle used.\n *\n * If `null`, the default bundle is being used.\n *\n * @since 7.0.0\n */\n currentBundleId: string | null;\n /**\n * Whether or not the app was reset to the default bundle.\n *\n * @since 7.0.0\n */\n rollback: boolean;\n}\n\n/**\n * @since 5.0.0\n */\nexport interface SetBundleOptions {\n /**\n * The unique identifier of the bundle to use.\n *\n * @since 5.0.0\n * @example '1.0.0'\n */\n bundleId: string;\n}\n\n/**\n * @since 5.0.0\n */\nexport interface SetChannelOptions {\n /**\n * The channel name.\n *\n * Set `null` to remove the channel.\n *\n * @since 5.0.0\n */\n channel: string | null;\n}\n\n/**\n * @since 7.4.0\n */\nexport interface SetConfigOptions {\n /**\n * The app ID used to identify the app.\n *\n * Set `null` to reset to the value from the Capacitor config file.\n *\n * @since 7.4.0\n * @example '6e351b4f-69a7-415e-a057-4567df7ffe94'\n */\n appId?: string | null;\n}\n\n/**\n * @since 5.0.0\n */\nexport interface SetCustomIdOptions {\n /**\n * The custom identifier of the device.\n *\n * Set `null` to remove the custom identifier.\n *\n * @since 5.0.0\n */\n customId: string | null;\n}\n\n/**\n * @since 6.7.0\n */\nexport interface SetNextBundleOptions {\n /**\n * The unique identifier of the bundle to use.\n *\n * Set `null` to use the default bundle (same as calling `reset()`).\n *\n * @since 6.7.0\n * @example '1.0.0'\n */\n bundleId: string | null;\n}\n\n/**\n * @since 6.7.0\n */\nexport interface SyncOptions {\n /**\n * The name of the channel where the latest bundle is fetched from.\n *\n * @since 6.7.0\n */\n channel?: string;\n}\n\n/**\n * @since 5.0.0\n */\nexport interface SyncResult {\n /**\n * The identifier of the next bundle to use.\n *\n * If `null`, the app is up-to-date and no new bundle is available.\n *\n * @since 5.0.0\n */\n nextBundleId: string | null;\n}\n\n/**\n * Listener for the download progress of a bundle.\n *\n * @since 7.0.0\n */\nexport type DownloadBundleProgressListener = (\n event: DownloadBundleProgressEvent,\n) => void;\n\n/**\n * Event that is triggered when the download progress of a bundle changes.\n *\n * @since 7.0.0\n */\nexport interface DownloadBundleProgressEvent {\n /**\n * The unique identifier of the bundle that is being downloaded.\n *\n * @since 7.0.0\n */\n bundleId: string;\n /**\n * The number of bytes that have been downloaded.\n *\n * @since 7.0.0\n */\n downloadedBytes: number;\n /**\n * The progress of the download in percent as a value between `0` and `1`.\n *\n * @since 7.0.0\n * @example 0.5\n */\n progress: number;\n /**\n * The total number of bytes to download.\n *\n * @since 7.0.0\n */\n totalBytes: number;\n}\n\n/**\n * Listener for when a bundle is set as the next bundle.\n *\n * @since 7.3.0\n */\nexport type NextBundleSetListener = (event: NextBundleSetEvent) => void;\n\n/**\n * Event that is triggered when a bundle is set as the next bundle.\n *\n * @since 7.3.0\n */\nexport interface NextBundleSetEvent {\n /**\n * The unique identifier of the bundle that is set as the next bundle.\n *\n * If `null`, the default bundle will be used.\n *\n * @since 7.3.0\n * @example '1.0.0'\n */\n bundleId: string | null;\n}\n\n/**\n * Listener for when the app is reloaded.\n *\n * @since 7.4.0\n */\nexport type ReloadedListener = () => void;\n"]}
1
+ {"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"AAAA,wCAAwC","sourcesContent":["/// <reference types=\"@capacitor/cli\" />\n\nimport type { PluginListenerHandle } from '@capacitor/core';\n\ndeclare module '@capacitor/cli' {\n export interface PluginsConfig {\n LiveUpdate?: {\n /**\n * The app ID is used to identify the app when using [Capawesome Cloud](https://capawesome.io/cloud/).\n *\n * This is **NOT** the same as the app identifier (e.g. `com.example.app`).\n * This is a unique identifier generated by Capawesome Cloud (e.g. `6e351b4f-69a7-415e-a057-4567df7ffe94`).\n *\n * @since 5.0.0\n * @example '6e351b4f-69a7-415e-a057-4567df7ffe94'\n */\n appId?: string;\n /**\n * Whether or not to automatically block bundles that have been rolled back.\n *\n * When enabled, the plugin will automatically block bundles that caused a rollback\n * (up to 100 bundles). When the limit is reached, the oldest blocked bundle is unblocked.\n * Blocked bundles will be skipped in future sync operations.\n *\n * **Attention**: This option has no effect if `readyTimeout` is set to `0`.\n *\n * Only available on Android and iOS.\n *\n * @since 7.3.0\n * @default false\n */\n autoBlockRolledBackBundles?: boolean;\n /**\n * Whether or not to automatically delete unused bundles.\n *\n * When enabled, the plugin will automatically delete unused bundles after calling `ready()`.\n *\n * @since 5.0.0\n * @default false\n */\n autoDeleteBundles?: boolean;\n /**\n * The auto-update strategy for live updates.\n *\n * - `none`: Live updates will not be applied automatically.\n * - `background`: Live updates will be automatically downloaded\n * and applied in the background at app startup and when the app resumes\n * (if the last check was more than 15 minutes ago).\n *\n * Only available on Android and iOS.\n *\n * @since 7.3.0\n * @default 'none'\n * @example 'background'\n */\n autoUpdateStrategy?: 'none' | 'background';\n /**\n * The default channel of the app.\n *\n * @since 6.3.0\n * @example 'production'\n */\n defaultChannel?: string;\n /**\n * The timeout in milliseconds for HTTP requests.\n *\n * @since 6.4.0\n * @default 60000\n */\n httpTimeout?: number;\n /**\n * The public key to verify the integrity of the bundle.\n *\n * The public key must be a PEM-encoded RSA public key.\n *\n * @since 6.1.0\n * @example '-----BEGIN PUBLIC KEY-----MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDDodf1SD0OOn6hIlDuKBza0Ed0OqtwyVJwiyjmE9BJaZ7y8ZUfcF+SKmd0l2cDPM45XIg2tAFux5n29uoKyHwSt+6tCi5CJA5Z1/1eZruRRqABLonV77KS3HUtvOgqRLDnKSV89dYZkM++NwmzOPgIF422mvc+VukcVOBfc8/AHQIDAQAB-----END PUBLIC KEY-----'\n */\n publicKey?: string;\n /**\n * The timeout in milliseconds to wait for the app to be ready\n * before resetting to the default bundle.\n *\n * It is strongly **recommended** to configure this option (e.g. `10000` ms)\n * so that the plugin can roll back to the default bundle in case of problems.\n * If configured, the plugin will wait for the app to call the `ready()`\n * method before resetting to the default bundle.\n *\n * Set to `0` to disable the timeout.\n *\n * @since 5.0.0\n * @default 0\n * @example 10000\n */\n readyTimeout?: number;\n /**\n * The API domain of the [Capawesome Cloud](https://cloud.capawesome.io) server **without** scheme or path.\n *\n * @since 7.0.0\n * @default 'api.cloud.capawesome.io'\n * @example 'api.cloud.capawesome.eu'\n */\n serverDomain?: string;\n };\n }\n}\n\nexport interface LiveUpdatePlugin {\n /**\n * Clear all blocked bundles from the blocked list.\n *\n * This removes all bundle identifiers that were automatically blocked\n * due to rollbacks when `autoBlockRolledBackBundles` is enabled.\n *\n * Only available on Android and iOS.\n *\n * @since 7.4.0\n */\n clearBlockedBundles(): Promise<void>;\n /**\n * Delete a bundle from the app.\n *\n * Only available on Android and iOS.\n *\n * @since 5.0.0\n */\n deleteBundle(options: DeleteBundleOptions): Promise<void>;\n /**\n * Download a bundle.\n *\n * Only available on Android and iOS.\n *\n * @since 5.0.0\n */\n downloadBundle(options: DownloadBundleOptions): Promise<void>;\n /**\n * Fetch the latest bundle using the [Capawesome Cloud](https://capawesome.io/cloud/).\n *\n * Only available on Android and iOS.\n *\n * @since 6.6.0\n */\n fetchLatestBundle(\n options?: FetchLatestBundleOptions,\n ): Promise<FetchLatestBundleResult>;\n /**\n * Get all blocked bundle identifiers.\n *\n * Returns the list of bundle identifiers that were automatically blocked\n * due to rollbacks when `autoBlockRolledBackBundles` is enabled.\n *\n * Only available on Android and iOS.\n *\n * @since 7.4.0\n */\n getBlockedBundles(): Promise<GetBlockedBundlesResult>;\n /**\n * Get all identifiers of bundles that have been downloaded.\n *\n * Only available on Android and iOS.\n *\n * @since 5.0.0\n * @deprecated Use `getDownloadedBundles()` instead.\n */\n getBundles(): Promise<GetBundlesResult>;\n /**\n * Get the channel that is used for the update.\n *\n * Only available on Android and iOS.\n *\n * @since 5.0.0\n */\n getChannel(): Promise<GetChannelResult>;\n /**\n * Get the runtime configuration.\n *\n * Returns the current plugin configuration including any runtime\n * overrides set via `setConfig()`.\n *\n * Only available on Android and iOS.\n *\n * @since 7.4.0\n */\n getConfig(): Promise<GetConfigResult>;\n /**\n * Get all identifiers of bundles that have been downloaded.\n *\n * Only available on Android and iOS.\n *\n * @since 7.4.0\n */\n getDownloadedBundles(): Promise<GetDownloadedBundlesResult>;\n /**\n * Get the bundle identifier of the current bundle.\n * The current bundle is the bundle that is currently used by the app.\n *\n * Only available on Android and iOS.\n *\n * @since 6.7.0\n */\n getCurrentBundle(): Promise<GetCurrentBundleResult>;\n /**\n * Get the custom identifier of the device.\n *\n * Only available on Android and iOS.\n *\n * @since 5.0.0\n */\n getCustomId(): Promise<GetCustomIdResult>;\n /**\n * Get the unique device identifier.\n *\n * Only available on Android and iOS.\n *\n * @since 5.0.0\n */\n getDeviceId(): Promise<GetDeviceIdResult>;\n /**\n * Check whether a sync operation is currently in progress.\n *\n * Only available on Android and iOS.\n *\n * @since 7.4.0\n */\n isSyncing(): Promise<IsSyncingResult>;\n /**\n * Get the bundle identifier of the next bundle.\n * The next bundle is the bundle that will be used after calling `reload()`\n * or restarting the app.\n *\n * Only available on Android and iOS.\n *\n * @since 6.7.0\n */\n getNextBundle(): Promise<GetNextBundleResult>;\n /**\n * Get the version code of the app.\n *\n * On **Android**, this is the `versionCode` from the `android/app/build.gradle` file.\n * On **iOS**, this is the `CFBundleVersion` from the `Info.plist` file.\n *\n * Only available on Android and iOS.\n *\n * @since 5.0.0\n */\n getVersionCode(): Promise<GetVersionCodeResult>;\n /**\n * Get the version name of the app.\n *\n * On **Android**, this is the `versionName` from the `android/app/build.gradle` file.\n * On **iOS**, this is the `CFBundleShortVersionString` from the `Info.plist` file.\n *\n * Only available on Android and iOS.\n *\n * @since 5.0.0\n */\n getVersionName(): Promise<GetVersionNameResult>;\n /**\n * Notify the plugin that the app is ready to use and no rollback is needed.\n *\n * **Attention**: This method should be called as soon as the app is ready to use\n * to prevent the app from being reset to the default bundle.\n *\n * Only available on Android and iOS.\n *\n * @since 5.0.0\n */\n ready(): Promise<ReadyResult>;\n /**\n * Reload the app to apply the new bundle.\n *\n * Only available on Android and iOS.\n *\n * @since 5.0.0\n */\n reload(): Promise<void>;\n /**\n * Reset the app to the default bundle.\n *\n * Call `reload()` or restart the app to apply the changes.\n *\n * Only available on Android and iOS.\n *\n * @since 5.0.0\n */\n reset(): Promise<void>;\n /**\n * Reset the runtime configuration to the values from the Capacitor config file.\n *\n * This clears any runtime configuration set via `setConfig()`.\n * The changes take effect immediately.\n *\n * Only available on Android and iOS.\n *\n * @since 7.4.0\n */\n resetConfig(): Promise<void>;\n /**\n * Set the channel to use for the update.\n *\n * Only available on Android and iOS.\n *\n * @since 5.0.0\n */\n setChannel(options: SetChannelOptions): Promise<void>;\n /**\n * Set the runtime configuration.\n *\n * This allows updating plugin configuration options at runtime.\n * The changes are persisted across app restarts and take effect immediately.\n *\n * **Important:** Runtime configuration is automatically reset to default values\n * whenever the native app is updated to a new version. This ensures that\n * configuration from previous versions doesn't persist after an app update.\n *\n * Only available on Android and iOS.\n *\n * @since 7.4.0\n */\n setConfig(options: SetConfigOptions): Promise<void>;\n /**\n * Set the custom identifier of the device.\n *\n * Only available on Android and iOS.\n *\n * @since 5.0.0\n */\n setCustomId(options: SetCustomIdOptions): Promise<void>;\n /**\n * Set the next bundle to use for the app.\n *\n * Call `reload()` or restart the app to apply the changes.\n *\n * Only available on Android and iOS.\n *\n * @since 6.7.0\n */\n setNextBundle(options: SetNextBundleOptions): Promise<void>;\n /**\n * Automatically download and set the latest bundle for the app using the [Capawesome Cloud](https://capawesome.io/cloud/).\n *\n * Call `reload()` or restart the app to apply the changes.\n *\n * Only available on Android and iOS.\n *\n * @since 5.0.0\n */\n sync(options?: SyncOptions): Promise<SyncResult>;\n /**\n * Listen for the download progress of a bundle.\n *\n * Only available on Android and iOS.\n *\n * @since 7.0.0\n */\n addListener(\n eventName: 'downloadBundleProgress',\n listenerFunc: DownloadBundleProgressListener,\n ): Promise<PluginListenerHandle>;\n /**\n * Listen for when a bundle is set as the next bundle.\n *\n * This event is triggered whenever a bundle is set to be used on the next app restart,\n * either through automatic updates or manual calls to `setNextBundle()`.\n *\n * Only available on Android and iOS.\n *\n * @since 7.3.0\n */\n addListener(\n eventName: 'nextBundleSet',\n listenerFunc: NextBundleSetListener,\n ): Promise<PluginListenerHandle>;\n /**\n * Listen for when the app is reloaded.\n *\n * This event is triggered after the `reload()` method is called\n * and the app has been reloaded.\n *\n * **Note:** To verify whether an update was successfully applied after a reload,\n * use the `ready()` method instead. The `ready()` method provides detailed information\n * about the current bundle, previous bundle, and whether a rollback occurred.\n *\n * Only available on Android and iOS.\n *\n * @since 7.4.0\n */\n addListener(\n eventName: 'reloaded',\n listenerFunc: ReloadedListener,\n ): Promise<PluginListenerHandle>;\n /**\n * Remove all listeners for this plugin.\n *\n * @since 7.2.0\n */\n removeAllListeners(): Promise<void>;\n}\n\n/**\n * @since 5.0.0\n */\nexport interface DeleteBundleOptions {\n /**\n * The unique identifier of the bundle to delete.\n *\n * @since 5.0.0\n * @example '1.0.0'\n */\n bundleId: string;\n}\n\nexport interface DownloadBundleOptions {\n /**\n * The artifact type of the bundle.\n *\n * @since 6.6.0\n * @default 'zip'\n * @example 'manifest'\n */\n artifactType?: 'manifest' | 'zip';\n /**\n * The unique identifier of the bundle.\n *\n * **Attention**: The value `public` is reserved and cannot be used as a bundle identifier.\n *\n * @since 5.0.0\n * @example '1.0.0'\n */\n bundleId: string;\n /**\n * The checksum of the self-hosted bundle as a SHA-256 hash\n * in hex format to verify the integrity of the bundle.\n *\n * **Attention**: Only supported for the `zip` artifact type.\n *\n * @since 7.1.0\n */\n checksum?: string;\n /**\n * The signature of the self-hosted bundle as a signed SHA-256 hash\n * in base64 format to verify the integrity of the bundle.\n *\n * **Attention**: Only supported for the `zip` artifact type.\n *\n * @since 7.1.0\n */\n signature?: string;\n /**\n * The URL of the bundle to download.\n *\n * For the `zip` artifact type, the URL must point to a ZIP file.\n * For the `manifest` artifact type, the URL serves as the base URL\n * to download the individual files. For example, if the URL is\n * `https://example.com/download`, the plugin will download the file\n * with the href `index.html` from `https://example.com/download?href=index.html`.\n *\n * To **verify the integrity** of the file, the server should return\n * a `X-Checksum` header with the SHA-256 hash in hex format.\n *\n * To **verify the signature** of the file, the server should return\n * a `X-Signature` header with the signed SHA-256 hash in base64 format.\n *\n * @since 5.0.0\n * @example 'https://example.com/bundle.zip'\n */\n url: string;\n}\n\n/**\n * @since 6.7.0\n */\nexport interface FetchLatestBundleOptions {\n /**\n * The name of the channel where the latest bundle is fetched from.\n *\n * @since 6.7.0\n */\n channel?: string;\n}\n\n/**\n * @since 6.6.0\n */\nexport interface FetchLatestBundleResult {\n /**\n * The artifact type of the bundle.\n *\n * @since 6.7.0\n */\n artifactType?: 'manifest' | 'zip';\n /**\n * The unique identifier of the latest bundle.\n *\n * If `null`, no bundle is available.\n *\n * @since 6.6.0\n */\n bundleId: string | null;\n /**\n * The checksum of the latest bundle if the bundle is self-hosted.\n *\n * If the bundle is hosted on Capawesome Cloud, the checksum will be\n * returned as response header when downloading the bundle.\n *\n * @since 7.1.0\n */\n checksum?: string;\n /**\n * Custom properties that are associated with the latest bundle.\n *\n * @since 7.0.0\n * @example { \"key\": \"value\" }\n */\n customProperties?: { [key: string]: string };\n /**\n * The URL of the latest bundle to download.\n * Pass this URL to the `downloadBundle(...)` method to download the bundle.\n *\n * @since 6.7.0\n */\n downloadUrl?: string;\n /**\n * The signature of the latest bundle if the bundle is self-hosted.\n *\n * If the bundle is hosted on Capawesome Cloud, the signature will be\n * returned as response header when downloading the bundle.\n *\n * @since 7.1.0\n */\n signature?: string;\n}\n\n/**\n * @since 5.0.0\n */\nexport interface GetBundleResult {\n /**\n * The unique identifier of the active bundle.\n *\n * If `null`, the default bundle is being used.\n *\n * @since 5.0.0\n * @example '1.0.0'\n */\n bundleId: string | null;\n}\n\n/**\n * @since 7.4.0\n */\nexport interface GetBlockedBundlesResult {\n /**\n * An array of unique identifiers of all blocked bundles.\n *\n * @since 7.4.0\n */\n bundleIds: string[];\n}\n\n/**\n * @since 5.0.0\n */\nexport interface GetBundlesResult {\n /**\n * An array of unique identifiers of all available bundles.\n *\n * @since 5.0.0\n */\n bundleIds: string[];\n}\n\n/**\n * @since 7.4.0\n */\nexport interface GetDownloadedBundlesResult {\n /**\n * An array of unique identifiers of all downloaded bundles.\n *\n * @since 7.4.0\n */\n bundleIds: string[];\n}\n\n/**\n * @since 5.0.0\n */\nexport interface GetChannelResult {\n /**\n * The channel name.\n *\n * If `null`, the app is using the default channel.\n *\n * @since 5.0.0\n * @example 'production'\n */\n channel: string | null;\n}\n\n/**\n * @since 7.4.0\n */\nexport interface GetConfigResult {\n /**\n * The app ID used to identify the app.\n *\n * If `null`, no app ID is configured.\n *\n * @since 7.4.0\n * @example '6e351b4f-69a7-415e-a057-4567df7ffe94'\n */\n appId: string | null;\n /**\n * The auto-update strategy for live updates.\n *\n * @since 7.4.0\n * @example 'background'\n */\n autoUpdateStrategy: 'none' | 'background';\n}\n\n/**\n * @since 6.7.0\n */\nexport interface GetCurrentBundleResult {\n /**\n * The unique identifier of the current bundle.\n *\n * If `null`, the default bundle is being used.\n *\n * @since 6.7.0\n */\n bundleId: string | null;\n}\n\n/**\n * @since 5.0.0\n */\nexport interface GetDeviceIdResult {\n /**\n * The unique identifier of the device.\n *\n * On iOS, [`identifierForVendor`](https://developer.apple.com/documentation/uikit/uidevice/1620059-identifierforvendor) is used.\n * The value of this property is the same for apps that come from the same vendor running on the same device.\n *\n * @since 5.0.0\n *\n * @example '50d2a548-80b7-4dad-adc7-97c0e79d8a89'\n */\n deviceId: string;\n}\n\n/**\n * @since 7.4.0\n */\nexport interface IsSyncingResult {\n /**\n * Whether a sync operation is currently in progress.\n *\n * @since 7.4.0\n */\n syncing: boolean;\n}\n\n/**\n * @since 6.7.0\n */\nexport interface GetNextBundleResult {\n /**\n * The unique identifier of the next bundle.\n *\n * If `null`, the default bundle is being used.\n *\n * @since 6.7.0\n */\n bundleId: string | null;\n}\n\n/**\n * @since 5.0.0\n */\nexport interface GetVersionCodeResult {\n /**\n * The version code of the app.\n *\n * On **Android**, this is the `versionCode` from the `android/app/build.gradle` file.\n * On **iOS**, this is the `CFBundleVersion` from the `Info.plist` file.\n *\n * @since 5.0.0\n * @example \"1\"\n */\n versionCode: string;\n}\n\n/**\n * @since 5.0.0\n */\nexport interface GetVersionNameResult {\n /**\n * The version name of the app.\n *\n * On **Android**, this is the `versionName` from the `android/app/build.gradle` file.\n * On **iOS**, this is the `CFBundleShortVersionString` from the `Info.plist` file.\n *\n * @since 5.0.0\n * @example \"1.0.0\"\n */\n versionName: string;\n}\n\n/**\n * @since 5.0.0\n */\nexport interface GetCustomIdResult {\n /**\n * The custom identifier of the device.\n *\n * If `null`, no custom identifier is set.\n *\n * @since 5.0.0\n * @example '50d2a548-80b7-4dad-adc7-97c0e79d8a89'\n */\n customId: string | null;\n}\n\n/**\n * @since 7.0.0\n */\nexport interface ReadyResult {\n /**\n * The identifier of the previous bundle used.\n *\n * If `null`, the default bundle was used.\n *\n * @since 7.0.0\n */\n previousBundleId: string | null;\n /**\n * The identifier of the current bundle used.\n *\n * If `null`, the default bundle is being used.\n *\n * @since 7.0.0\n */\n currentBundleId: string | null;\n /**\n * Whether or not the app was reset to the default bundle.\n *\n * @since 7.0.0\n */\n rollback: boolean;\n}\n\n/**\n * @since 5.0.0\n */\nexport interface SetBundleOptions {\n /**\n * The unique identifier of the bundle to use.\n *\n * @since 5.0.0\n * @example '1.0.0'\n */\n bundleId: string;\n}\n\n/**\n * @since 5.0.0\n */\nexport interface SetChannelOptions {\n /**\n * The channel name.\n *\n * Set `null` to remove the channel.\n *\n * @since 5.0.0\n */\n channel: string | null;\n}\n\n/**\n * @since 7.4.0\n */\nexport interface SetConfigOptions {\n /**\n * The app ID used to identify the app.\n *\n * Set `null` to reset to the value from the Capacitor config file.\n *\n * @since 7.4.0\n * @example '6e351b4f-69a7-415e-a057-4567df7ffe94'\n */\n appId?: string | null;\n}\n\n/**\n * @since 5.0.0\n */\nexport interface SetCustomIdOptions {\n /**\n * The custom identifier of the device.\n *\n * Set `null` to remove the custom identifier.\n *\n * @since 5.0.0\n */\n customId: string | null;\n}\n\n/**\n * @since 6.7.0\n */\nexport interface SetNextBundleOptions {\n /**\n * The unique identifier of the bundle to use.\n *\n * Set `null` to use the default bundle (same as calling `reset()`).\n *\n * @since 6.7.0\n * @example '1.0.0'\n */\n bundleId: string | null;\n}\n\n/**\n * @since 6.7.0\n */\nexport interface SyncOptions {\n /**\n * The name of the channel where the latest bundle is fetched from.\n *\n * @since 6.7.0\n */\n channel?: string;\n}\n\n/**\n * @since 5.0.0\n */\nexport interface SyncResult {\n /**\n * The identifier of the next bundle to use.\n *\n * If `null`, the app is up-to-date and no new bundle is available.\n *\n * @since 5.0.0\n */\n nextBundleId: string | null;\n}\n\n/**\n * Listener for the download progress of a bundle.\n *\n * @since 7.0.0\n */\nexport type DownloadBundleProgressListener = (\n event: DownloadBundleProgressEvent,\n) => void;\n\n/**\n * Event that is triggered when the download progress of a bundle changes.\n *\n * @since 7.0.0\n */\nexport interface DownloadBundleProgressEvent {\n /**\n * The unique identifier of the bundle that is being downloaded.\n *\n * @since 7.0.0\n */\n bundleId: string;\n /**\n * The number of bytes that have been downloaded.\n *\n * @since 7.0.0\n */\n downloadedBytes: number;\n /**\n * The progress of the download in percent as a value between `0` and `1`.\n *\n * @since 7.0.0\n * @example 0.5\n */\n progress: number;\n /**\n * The total number of bytes to download.\n *\n * @since 7.0.0\n */\n totalBytes: number;\n}\n\n/**\n * Listener for when a bundle is set as the next bundle.\n *\n * @since 7.3.0\n */\nexport type NextBundleSetListener = (event: NextBundleSetEvent) => void;\n\n/**\n * Event that is triggered when a bundle is set as the next bundle.\n *\n * @since 7.3.0\n */\nexport interface NextBundleSetEvent {\n /**\n * The unique identifier of the bundle that is set as the next bundle.\n *\n * If `null`, the default bundle will be used.\n *\n * @since 7.3.0\n * @example '1.0.0'\n */\n bundleId: string | null;\n}\n\n/**\n * Listener for when the app is reloaded.\n *\n * @since 7.4.0\n */\nexport type ReloadedListener = () => void;\n"]}
@@ -7,20 +7,16 @@ import CommonCrypto
7
7
 
8
8
  // swiftlint:disable type_body_length
9
9
  @objc public class LiveUpdate: NSObject {
10
- public static let tag = "LiveUpdate"
11
- public static let version = "8.1.1"
12
-
13
10
  private let autoUpdateIntervalMs: Int64 = 15 * 60 * 1000 // 15 minutes
14
- private let bridge: CAPBridgeProtocol
15
11
  private let bundlesDirectory = "NoCloud/ionic_built_snapshots" // DO NOT CHANGE! (See https://dub.sh/BLluidt)
16
12
  private let cachesDirectoryUrl = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first!
17
13
  private let config: LiveUpdateConfig
18
14
  private let defaultWebAssetDir = "public" // DO NOT CHANGE! (See https://dub.sh/Buvz4yj)
19
15
  private let defaultServerPathKey = "serverBasePath" // DO NOT CHANGE! (See https://dub.sh/ceDl0zT)
20
- private let eventEmitter: LiveUpdateEventEmitter
21
16
  private let httpClient: LiveUpdateHttpClient
22
17
  private let libraryDirectoryUrl = FileManager.default.urls(for: .libraryDirectory, in: .userDomainMask).first!
23
18
  private let manifestFileName = "capawesome-live-update-manifest.json" // DO NOT CHANGE!
19
+ private let plugin: LiveUpdatePlugin
24
20
  private let preferences: LiveUpdatePreferences
25
21
 
26
22
  private var rollbackDispatchWorkItem: DispatchWorkItem?
@@ -28,11 +24,10 @@ import CommonCrypto
28
24
  private var lastAutoUpdateCheckTimestamp: Int64 = 0
29
25
  private var syncInProgress = false
30
26
 
31
- init(bridge: CAPBridgeProtocol, config: LiveUpdateConfig, eventEmitter: LiveUpdateEventEmitter) {
32
- self.bridge = bridge
27
+ init(config: LiveUpdateConfig, plugin: LiveUpdatePlugin) {
33
28
  self.config = config
34
- self.eventEmitter = eventEmitter
35
29
  self.httpClient = LiveUpdateHttpClient(config: config)
30
+ self.plugin = plugin
36
31
  self.preferences = LiveUpdatePreferences()
37
32
  super.init()
38
33
 
@@ -179,9 +174,9 @@ import CommonCrypto
179
174
  }
180
175
 
181
176
  @objc public func ready(completion: @escaping (Result?, Error?) -> Void) {
182
- CAPLog.print("[", LiveUpdate.tag, "] ", "App is ready.")
177
+ CAPLog.print("[", LiveUpdatePlugin.tag, "] ", "App is ready.")
183
178
  if config.readyTimeout <= 0 {
184
- CAPLog.print("[", LiveUpdate.tag, "] ", "Ready timeout is set to 0. Automatic rollback is disabled.")
179
+ CAPLog.print("[", LiveUpdatePlugin.tag, "] ", "Ready timeout is set to 0. Automatic rollback is disabled.")
185
180
  }
186
181
  // Stop the rollback timer
187
182
  stopRollbackTimer()
@@ -269,7 +264,7 @@ import CommonCrypto
269
264
  // Fetch the latest bundle
270
265
  let fetchLatestBundleOptions = FetchLatestBundleOptions(channel: channel)
271
266
  guard let response = try await fetchLatestBundle(fetchLatestBundleOptions) else {
272
- CAPLog.print("[", LiveUpdate.tag, "] ", "No update available.")
267
+ CAPLog.print("[", LiveUpdatePlugin.tag, "] ", "No update available.")
273
268
  return SyncResult(nextBundleId: nil)
274
269
  }
275
270
  let artifactType = response.artifactType
@@ -279,7 +274,7 @@ import CommonCrypto
279
274
  let downloadUrl = response.url
280
275
  // Check if the bundle is blocked
281
276
  if isBlockedBundleId(latestBundleId) {
282
- CAPLog.print("[", LiveUpdate.tag, "] ", "Bundle is blocked and will not be downloaded.")
277
+ CAPLog.print("[", LiveUpdatePlugin.tag, "] ", "Bundle is blocked and will not be downloaded.")
283
278
  return SyncResult(nextBundleId: nil)
284
279
  }
285
280
  // Check if bundle already exists
@@ -377,7 +372,7 @@ import CommonCrypto
377
372
  for fileToCopy in filesToCopy {
378
373
  let success = tryCopyCurrentBundleFile(fileToCopy: fileToCopy, toDirectory: toDirectory)
379
374
  if !success {
380
- CAPLog.print("[", LiveUpdate.tag, "] ", "Failed to copy file: \(fileToCopy.href)")
375
+ CAPLog.print("[", LiveUpdatePlugin.tag, "] ", "Failed to copy file: \(fileToCopy.href)")
381
376
  // If the file could not be copied, add it to the list of missing items
382
377
  missingItems.append(fileToCopy)
383
378
  }
@@ -392,7 +387,7 @@ import CommonCrypto
392
387
  do {
393
388
  try FileManager.default.createDirectory(at: bundlesDirectoryUrl, withIntermediateDirectories: true, attributes: nil)
394
389
  } catch {
395
- CAPLog.print("[", LiveUpdate.tag, "] ", "Failed to create bundles directory.")
390
+ CAPLog.print("[", LiveUpdatePlugin.tag, "] ", "Failed to create bundles directory.")
396
391
  }
397
392
  }
398
393
  }
@@ -424,7 +419,7 @@ import CommonCrypto
424
419
  do {
425
420
  try deleteBundleById(bundleId)
426
421
  } catch {
427
- CAPLog.print("[", LiveUpdate.tag, "] ", "Failed to delete bundle with id: \(bundleId)")
422
+ CAPLog.print("[", LiveUpdatePlugin.tag, "] ", "Failed to delete bundle with id: \(bundleId)")
428
423
  }
429
424
  }
430
425
  }
@@ -437,7 +432,7 @@ import CommonCrypto
437
432
  let urlComponents = URLComponents(string: url)!
438
433
  let result = try await httpClient.download(url: urlComponents.asURL(), destination: destination, callback: callback)
439
434
  if let error = result.error {
440
- CAPLog.print("[", LiveUpdate.tag, "] ", "Failed to download file: \(error)")
435
+ CAPLog.print("[", LiveUpdatePlugin.tag, "] ", "Failed to download file: \(error)")
441
436
  if let urlError = error.underlyingError as? URLError {
442
437
  if urlError.code == .timedOut {
443
438
  throw urlError
@@ -559,14 +554,14 @@ import CommonCrypto
559
554
  parameters["deviceId"] = getDeviceId()
560
555
  parameters["osVersion"] = await UIDevice.current.systemVersion
561
556
  parameters["platform"] = "1"
562
- parameters["pluginVersion"] = LiveUpdate.version
557
+ parameters["pluginVersion"] = LiveUpdatePlugin.version
563
558
  var urlComponents = URLComponents(string: "https://\(config.serverDomain)/v1/apps/\(getAppId() ?? "")/bundles/latest")!
564
559
  urlComponents.queryItems = parameters.map { URLQueryItem(name: $0.key, value: $0.value) }
565
560
  let url = try urlComponents.asURL()
566
- CAPLog.print("[", LiveUpdate.tag, "] Fetching latest bundle: ", url)
561
+ CAPLog.print("[", LiveUpdatePlugin.tag, "] Fetching latest bundle: ", url)
567
562
  let response = try await self.httpClient.request(url: url, type: GetLatestBundleResponse.self)
568
563
  if let data = response.data {
569
- CAPLog.print("[", LiveUpdate.tag, "] Latest bundle response: ", String(decoding: data, as: UTF8.self))
564
+ CAPLog.print("[", LiveUpdatePlugin.tag, "] Latest bundle response: ", String(decoding: data, as: UTF8.self))
570
565
  }
571
566
  if let error = response.error {
572
567
  if let urlError = error.underlyingError as? URLError {
@@ -643,7 +638,7 @@ import CommonCrypto
643
638
 
644
639
  /// - Returns: The path to the current bundle directory or `nil` if no view controller was found.
645
640
  private func getCurrentCapacitorServerPath() -> String? {
646
- guard let viewController = self.bridge.viewController as? CAPBridgeViewController else {
641
+ guard let viewController = self.plugin.bridge?.viewController as? CAPBridgeViewController else {
647
642
  return nil
648
643
  }
649
644
  return viewController.getServerBasePath()
@@ -725,14 +720,14 @@ import CommonCrypto
725
720
  }
726
721
 
727
722
  private func notifyDownloadBundleProgressListeners(_ event: DownloadBundleProgressEvent) {
728
- eventEmitter.onDownloadBundleProgress(event)
723
+ plugin.notifyDownloadBundleProgressListeners(event)
729
724
  }
730
725
 
731
726
  private func performAutoUpdate() {
732
727
  // Check if enough time has passed since the last check
733
728
  let now = Int64(Date().timeIntervalSince1970 * 1000)
734
729
  if lastAutoUpdateCheckTimestamp > 0 && (now - lastAutoUpdateCheckTimestamp) < autoUpdateIntervalMs {
735
- CAPLog.print("[", LiveUpdate.tag, "] ", "Auto-update skipped. Last check was less than 15 minutes ago.")
730
+ CAPLog.print("[", LiveUpdatePlugin.tag, "] ", "Auto-update skipped. Last check was less than 15 minutes ago.")
736
731
  return
737
732
  }
738
733
 
@@ -742,12 +737,12 @@ import CommonCrypto
742
737
  // Run sync in background task
743
738
  Task {
744
739
  do {
745
- CAPLog.print("[", LiveUpdate.tag, "] ", "Auto-update started.")
740
+ CAPLog.print("[", LiveUpdatePlugin.tag, "] ", "Auto-update started.")
746
741
  let options = SyncOptions(channel: nil)
747
742
  _ = try await sync(options)
748
- CAPLog.print("[", LiveUpdate.tag, "] ", "Auto-update completed successfully.")
743
+ CAPLog.print("[", LiveUpdatePlugin.tag, "] ", "Auto-update completed successfully.")
749
744
  } catch {
750
- CAPLog.print("[", LiveUpdate.tag, "] ", "Auto-update failed: ", error.localizedDescription)
745
+ CAPLog.print("[", LiveUpdatePlugin.tag, "] ", "Auto-update failed: ", error.localizedDescription)
751
746
  }
752
747
  }
753
748
  }
@@ -760,11 +755,11 @@ import CommonCrypto
760
755
  setPreviousBundleId(bundleId: currentBundleId)
761
756
  // Perform the rollback
762
757
  if let _ = currentBundleId {
763
- CAPLog.print("[", LiveUpdate.tag, "] ", "App is not ready. Rolling back to default bundle.")
758
+ CAPLog.print("[", LiveUpdatePlugin.tag, "] ", "App is not ready. Rolling back to default bundle.")
764
759
  setNextBundleById(nil)
765
760
  setCurrentBundleById(nil)
766
761
  } else {
767
- CAPLog.print("[", LiveUpdate.tag, "] ", "App is not ready. Default bundle is already in use.")
762
+ CAPLog.print("[", LiveUpdatePlugin.tag, "] ", "App is not ready. Default bundle is already in use.")
768
763
  }
769
764
  }
770
765
 
@@ -790,7 +785,7 @@ import CommonCrypto
790
785
  }
791
786
  }
792
787
  } catch {
793
- CAPLog.print("[", LiveUpdate.tag, "] ", "Failed to search index.html file: \(error.localizedDescription)")
788
+ CAPLog.print("[", LiveUpdatePlugin.tag, "] ", "Failed to search index.html file: \(error.localizedDescription)")
794
789
  }
795
790
  return nil
796
791
  }
@@ -802,7 +797,7 @@ import CommonCrypto
802
797
  }
803
798
 
804
799
  private func setCurrentCapacitorServerPath(path: String) {
805
- guard let viewController = self.bridge.viewController as? CAPBridgeViewController else {
800
+ guard let viewController = self.plugin.bridge?.viewController as? CAPBridgeViewController else {
806
801
  return
807
802
  }
808
803
  viewController.setServerBasePath(path: path)
@@ -821,11 +816,11 @@ import CommonCrypto
821
816
 
822
817
  private func notifyNextBundleSetListeners(_ bundleId: String?) {
823
818
  let event = NextBundleSetEvent(bundleId: bundleId)
824
- eventEmitter.onNextBundleSet(event)
819
+ plugin.notifyNextBundleSetListeners(event)
825
820
  }
826
821
 
827
822
  private func notifyReloadedListeners() {
828
- eventEmitter.onReloaded()
823
+ plugin.notifyReloadedListeners()
829
824
  }
830
825
 
831
826
  private func addBlockedBundleId(_ bundleId: String) {
@@ -853,7 +848,7 @@ import CommonCrypto
853
848
  let newBlockedIds = blockedList.joined(separator: ",")
854
849
  preferences.setBlockedBundleIds(newBlockedIds)
855
850
 
856
- CAPLog.print("[", LiveUpdate.tag, "] ", "Bundle blocked: ", bundleId)
851
+ CAPLog.print("[", LiveUpdatePlugin.tag, "] ", "Bundle blocked: ", bundleId)
857
852
  }
858
853
 
859
854
  private func isBlockedBundleId(_ bundleId: String) -> Bool {
@@ -883,7 +878,7 @@ import CommonCrypto
883
878
 
884
879
  if lastVersionCode == nil || lastVersionName == nil || lastVersionCode != currentVersionCode || lastVersionName != currentVersionName {
885
880
  CAPLog.print(
886
- "[", LiveUpdate.tag, "] ",
881
+ "[", LiveUpdatePlugin.tag, "] ",
887
882
  "App version changed (last: \(lastVersionName ?? "nil")/\(lastVersionCode ?? "nil"), current: \(currentVersionName)/\(currentVersionCode)), resetting config."
888
883
  )
889
884
  resetConfig()
@@ -969,7 +964,7 @@ import CommonCrypto
969
964
  .replacingOccurrences(of: "-----END PUBLIC KEY-----", with: "")
970
965
  .replacingOccurrences(of: "\n", with: "")
971
966
  guard let publicKeyData = Data(base64Encoded: publicKeyAsBase64) else {
972
- CAPLog.print("[", LiveUpdate.tag, "] ", "Failed to decode public key.")
967
+ CAPLog.print("[", LiveUpdatePlugin.tag, "] ", "Failed to decode public key.")
973
968
  return false
974
969
  }
975
970
  let publicKeyAttributes: [CFString: Any] = [
@@ -981,12 +976,12 @@ import CommonCrypto
981
976
  var secKeyCreateWithDataError: Unmanaged<CFError>?
982
977
  guard let publicKey = SecKeyCreateWithData(publicKeyData as CFData, publicKeyAttributes as CFDictionary, &secKeyCreateWithDataError) else {
983
978
  if let error = secKeyCreateWithDataError?.takeRetainedValue() {
984
- CAPLog.print("[", LiveUpdate.tag, "] ", "Failed to create public key with error: \(error)")
979
+ CAPLog.print("[", LiveUpdatePlugin.tag, "] ", "Failed to create public key with error: \(error)")
985
980
  }
986
981
  return false
987
982
  }
988
983
  guard let signatureData = Data(base64Encoded: signature) else {
989
- CAPLog.print("[", LiveUpdate.tag, "] ", "Failed to decode signature.")
984
+ CAPLog.print("[", LiveUpdatePlugin.tag, "] ", "Failed to decode signature.")
990
985
  return false
991
986
  }
992
987
 
@@ -1016,7 +1011,7 @@ import CommonCrypto
1016
1011
  let signatureAlgorithm = SecKeyAlgorithm.rsaSignatureDigestPKCS1v15SHA256
1017
1012
  let verificationResult = SecKeyVerifySignature(publicKey, signatureAlgorithm, digest as CFData, signatureData as CFData, &secKeyVerifySignatureError)
1018
1013
  if let error = secKeyVerifySignatureError?.takeRetainedValue() {
1019
- CAPLog.print("[", LiveUpdate.tag, "] ", "Failed to verify signature with error: \(error)")
1014
+ CAPLog.print("[", LiveUpdatePlugin.tag, "] ", "Failed to verify signature with error: \(error)")
1020
1015
  }
1021
1016
  return verificationResult
1022
1017
  }
@@ -7,8 +7,9 @@ import Capacitor
7
7
  */
8
8
  @objc(LiveUpdatePlugin)
9
9
  public class LiveUpdatePlugin: CAPPlugin, CAPBridgedPlugin {
10
- public static let tag = LiveUpdate.tag
11
- public static let version = LiveUpdate.version
10
+ public static let tag = "LiveUpdate"
11
+ public static let version = "8.1.0"
12
+ public static let userDefaultsPrefix = "CapawesomeLiveUpdate" // DO NOT CHANGE
12
13
 
13
14
  public let identifier = "LiveUpdatePlugin"
14
15
  public let jsName = "LiveUpdate"
@@ -48,13 +49,8 @@ public class LiveUpdatePlugin: CAPPlugin, CAPBridgedPlugin {
48
49
  private var implementation: LiveUpdate?
49
50
 
50
51
  override public func load() {
51
- guard let bridge = bridge else {
52
- return
53
- }
54
- let config = liveUpdateConfig()
55
- self.config = config
56
- let eventEmitter = PluginLiveUpdateEventEmitter(plugin: self)
57
- self.implementation = LiveUpdate(bridge: bridge, config: config, eventEmitter: eventEmitter)
52
+ self.config = liveUpdateConfig()
53
+ self.implementation = LiveUpdate(config: config!, plugin: self)
58
54
 
59
55
  // Notify implementation about load
60
56
  implementation?.handleLoad()
@@ -426,24 +422,4 @@ public class LiveUpdatePlugin: CAPPlugin, CAPBridgedPlugin {
426
422
  private func resolveCall(_ call: CAPPluginCall, _ result: JSObject) {
427
423
  call.resolve(result)
428
424
  }
429
-
430
- private class PluginLiveUpdateEventEmitter: NSObject, LiveUpdateEventEmitter {
431
- weak var plugin: LiveUpdatePlugin?
432
-
433
- init(plugin: LiveUpdatePlugin) {
434
- self.plugin = plugin
435
- }
436
-
437
- func onDownloadBundleProgress(_ event: DownloadBundleProgressEvent) {
438
- plugin?.notifyDownloadBundleProgressListeners(event)
439
- }
440
-
441
- func onNextBundleSet(_ event: NextBundleSetEvent) {
442
- plugin?.notifyNextBundleSetListeners(event)
443
- }
444
-
445
- func onReloaded() {
446
- plugin?.notifyReloadedListeners()
447
- }
448
- }
449
425
  }
@@ -1,8 +1,6 @@
1
1
  import Foundation
2
2
 
3
3
  public class LiveUpdatePreferences: NSObject {
4
- private static let userDefaultsPrefix = "CapawesomeLiveUpdate" // DO NOT CHANGE
5
-
6
4
  private let appIdKey = "appId" // DO NOT CHANGE
7
5
  private let blockedBundleIdsKey = "blockedBundleIds" // DO NOT CHANGE
8
6
  private let channelKey = "channel" // DO NOT CHANGE
@@ -99,6 +97,6 @@ public class LiveUpdatePreferences: NSObject {
99
97
  }
100
98
 
101
99
  private func applyPrefix(to key: String) -> String {
102
- return LiveUpdatePreferences.userDefaultsPrefix + "." + key
100
+ return LiveUpdatePlugin.userDefaultsPrefix + "." + key
103
101
  }
104
102
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capawesome/capacitor-live-update",
3
- "version": "8.1.0-dev.c088829.1767373807",
3
+ "version": "8.1.1",
4
4
  "description": "Capacitor plugin to update your app remotely in real-time.",
5
5
  "main": "dist/plugin.cjs.js",
6
6
  "module": "dist/esm/index.js",
@@ -1,20 +0,0 @@
1
- package io.capawesome.capacitorjs.plugins.liveupdate.classes;
2
-
3
- import androidx.annotation.NonNull;
4
- import androidx.annotation.Nullable;
5
-
6
- public class CustomException extends Exception {
7
-
8
- @Nullable
9
- private final String code;
10
-
11
- public CustomException(@Nullable String code, @NonNull String message) {
12
- super(message);
13
- this.code = code;
14
- }
15
-
16
- @Nullable
17
- public String getCode() {
18
- return code;
19
- }
20
- }
@@ -1,33 +0,0 @@
1
- package io.capawesome.capacitorjs.plugins.liveupdate.classes;
2
-
3
- public class CustomExceptions {
4
-
5
- public static final CustomException APP_ID_MISSING = new CustomException("APP_ID_MISSING", "appId must be configured.");
6
- public static final CustomException BUNDLE_EXISTS = new CustomException("BUNDLE_EXISTS", "bundle already exists.");
7
- public static final CustomException BUNDLE_ID_MISSING = new CustomException(null, "bundleId must be provided.");
8
- public static final CustomException BUNDLE_INDEX_HTML_MISSING = new CustomException(
9
- "BUNDLE_INDEX_HTML_MISSING",
10
- "The bundle does not contain an index.html file."
11
- );
12
- public static final CustomException BUNDLE_NOT_FOUND = new CustomException("BUNDLE_NOT_FOUND", "bundle not found.");
13
- public static final CustomException CHECKSUM_CALCULATION_FAILED = new CustomException(
14
- "CHECKSUM_CALCULATION_FAILED",
15
- "Failed to calculate checksum."
16
- );
17
- public static final CustomException CHECKSUM_MISMATCH = new CustomException("CHECKSUM_MISMATCH", "Checksum mismatch.");
18
- public static final CustomException CUSTOM_ID_MISSING = new CustomException(null, "customId must be provided.");
19
- public static final CustomException DOWNLOAD_FAILED = new CustomException("DOWNLOAD_FAILED", "Bundle could not be downloaded.");
20
- public static final CustomException HTTP_TIMEOUT = new CustomException("HTTP_TIMEOUT", "Request timed out.");
21
- public static final CustomException URL_MISSING = new CustomException(null, "url must be provided.");
22
- public static final CustomException SIGNATURE_VERIFICATION_FAILED = new CustomException(
23
- "SIGNATURE_VERIFICATION_FAILED",
24
- "Signature verification failed."
25
- );
26
- public static final CustomException PUBLIC_KEY_INVALID = new CustomException("PUBLIC_KEY_INVALID", "Invalid public key.");
27
- public static final CustomException SIGNATURE_MISSING = new CustomException(
28
- "SIGNATURE_MISSING",
29
- "Bundle does not contain a signature."
30
- );
31
- public static final CustomException SYNC_IN_PROGRESS = new CustomException("SYNC_IN_PROGRESS", "Sync is already in progress.");
32
- public static final CustomException UNKNOWN_ERROR = new CustomException("UNKNOWN_ERROR", "An unknown error has occurred.");
33
- }
@@ -1,13 +0,0 @@
1
- package io.capawesome.capacitorjs.plugins.liveupdate.interfaces;
2
-
3
- import androidx.annotation.NonNull;
4
- import io.capawesome.capacitorjs.plugins.liveupdate.classes.events.DownloadBundleProgressEvent;
5
- import io.capawesome.capacitorjs.plugins.liveupdate.classes.events.NextBundleSetEvent;
6
-
7
- public interface LiveUpdateEventEmitter {
8
- void onDownloadBundleProgress(@NonNull DownloadBundleProgressEvent event);
9
-
10
- void onNextBundleSet(@NonNull NextBundleSetEvent event);
11
-
12
- void onReloaded();
13
- }
@@ -1,8 +0,0 @@
1
- import Foundation
2
- import Capacitor
3
-
4
- @objc public protocol LiveUpdateEventEmitter {
5
- func onDownloadBundleProgress(_ event: DownloadBundleProgressEvent)
6
- func onNextBundleSet(_ event: NextBundleSetEvent)
7
- func onReloaded()
8
- }