@capawesome/capacitor-live-update 8.4.1 → 8.4.3
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/Package.swift +1 -5
- package/README.md +51 -1
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/liveupdate/LiveUpdate.java +80 -55
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/liveupdate/LiveUpdatePlugin.java +2 -1
- package/dist/docs.json +2 -2
- package/dist/esm/definitions.d.ts +9 -0
- package/dist/esm/definitions.js.map +1 -1
- package/ios/Plugin/LiveUpdate.swift +37 -11
- package/ios/Plugin/LiveUpdatePlugin.swift +1 -1
- package/package.json +1 -1
package/Package.swift
CHANGED
|
@@ -23,10 +23,6 @@ let package = Package(
|
|
|
23
23
|
.product(name: "Alamofire", package: "Alamofire"),
|
|
24
24
|
.product(name: "ZIPFoundation", package: "ZIPFoundation")
|
|
25
25
|
],
|
|
26
|
-
path: "ios/Plugin")
|
|
27
|
-
.testTarget(
|
|
28
|
-
name: "LiveUpdatePluginTests",
|
|
29
|
-
dependencies: ["LiveUpdatePlugin"],
|
|
30
|
-
path: "ios/PluginTests")
|
|
26
|
+
path: "ios/Plugin")
|
|
31
27
|
]
|
|
32
28
|
)
|
package/README.md
CHANGED
|
@@ -55,9 +55,10 @@ The Live Update plugin is typically used to ship changes to users without going
|
|
|
55
55
|
|
|
56
56
|
- [Getting Started with Capawesome Cloud Live Updates](https://capawesome.io/docs/cloud/live-updates/setup/)
|
|
57
57
|
- [Capacitor Live Updates: The Complete OTA Guide](https://capawesome.io/blog/capacitor-live-updates-guide/)
|
|
58
|
-
- [Best
|
|
58
|
+
- [Best Live Update Tools for Capacitor (2026)](https://capawesome.io/blog/best-ota-update-tools-for-capacitor/)
|
|
59
59
|
- [Capacitor Live Updates: Signing vs Encryption](https://capawesome.io/blog/capacitor-live-updates-end-to-end-encryption/)
|
|
60
60
|
- [Capacitor Live Updates: Reliability & Uptime](https://capawesome.io/blog/capacitor-live-updates-reliability-and-uptime/)
|
|
61
|
+
- [Capawesome vs. Capgo: Which Is More Reliable?](https://capawesome.io/blog/capawesome-cloud-vs-capgo-reliability/)
|
|
61
62
|
- [Migrating from Ionic Appflow to Capawesome Cloud](https://capawesome.io/blog/migrating-from-ionic-appflow-to-capawesome-cloud/)
|
|
62
63
|
- [Migrating from App Center to Capawesome Cloud](https://capawesome.io/blog/migrating-from-app-center-to-capawesome-cloud/)
|
|
63
64
|
- [Live Updates for Nuxt Capacitor Apps](https://capawesome.io/blog/live-updates-for-nuxt-capacitor/)
|
|
@@ -813,6 +814,7 @@ Notify the plugin that the app is ready to use and no rollback is needed.
|
|
|
813
814
|
|
|
814
815
|
**Attention**: This method should be called as soon as the app is ready to use
|
|
815
816
|
to prevent the app from being reset to the default bundle.
|
|
817
|
+
It must always be called before `sync(...)` or any other method that changes the bundle.
|
|
816
818
|
|
|
817
819
|
Only available on Android and iOS.
|
|
818
820
|
|
|
@@ -831,6 +833,14 @@ reload() => Promise<void>
|
|
|
831
833
|
|
|
832
834
|
Reload the app to apply the new bundle.
|
|
833
835
|
|
|
836
|
+
This method reloads the web view only, the native process is **not** restarted.
|
|
837
|
+
Resources of the web layer that hold an exclusive lock (e.g. IndexedDB or WebSockets)
|
|
838
|
+
are therefore not released automatically and may prevent the new bundle from starting.
|
|
839
|
+
Release these resources before calling this method or apply the new bundle
|
|
840
|
+
on the next app start instead.
|
|
841
|
+
|
|
842
|
+
**Attention**: The in-memory state of the app (e.g. unsaved user input) is lost.
|
|
843
|
+
|
|
834
844
|
Only available on Android and iOS.
|
|
835
845
|
|
|
836
846
|
**Since:** 5.0.0
|
|
@@ -1346,6 +1356,23 @@ const sync = async () => {
|
|
|
1346
1356
|
|
|
1347
1357
|
This way, the app will check for updates, but no updates will be found.
|
|
1348
1358
|
|
|
1359
|
+
### Check which bundle is running
|
|
1360
|
+
|
|
1361
|
+
If an update does not seem to be applied, log the identifier of the current bundle and the path that the web view is serving as early as possible at app start:
|
|
1362
|
+
|
|
1363
|
+
```typescript
|
|
1364
|
+
import { WebView } from '@capacitor/core';
|
|
1365
|
+
import { LiveUpdate } from '@capawesome/capacitor-live-update';
|
|
1366
|
+
|
|
1367
|
+
const logCurrentBundle = async () => {
|
|
1368
|
+
const { bundleId } = await LiveUpdate.getCurrentBundle();
|
|
1369
|
+
const { path } = await WebView.getServerBasePath();
|
|
1370
|
+
console.log(`Bundle: ${bundleId ?? 'default'} (${path})`);
|
|
1371
|
+
};
|
|
1372
|
+
```
|
|
1373
|
+
|
|
1374
|
+
Because [`reload()`](#reload) restarts the web layer, this also logs both values after a reload. If they change after the reload, the new bundle was applied and any remaining problem is in the web layer of your app (see [Why does my app hang after calling `reload()`?](#why-does-my-app-hang-after-calling-reload)).
|
|
1375
|
+
|
|
1349
1376
|
## Limitations
|
|
1350
1377
|
|
|
1351
1378
|
Live updates are only supported for [binary-compatible changes](https://capawesome.io/docs/cloud/live-updates/faq/#what-are-binary-compatible-changes) (e.g. HTML, CSS, JavaScript).
|
|
@@ -1394,10 +1421,33 @@ No, the plugin also supports self-hosted bundles. You can download a bundle from
|
|
|
1394
1421
|
|
|
1395
1422
|
Live updates are only supported for [binary-compatible changes](https://capawesome.io/docs/cloud/live-updates/faq/#what-are-binary-compatible-changes) such as HTML, CSS, and JavaScript. If you change native code, for example by adding a new plugin, you need to resubmit your app to the app stores. You should therefore [restrict live updates to compatible native versions](https://capawesome.io/blog/how-to-restrict-capacitor-live-updates-to-native-versions/) of your app, as described in the [Limitations](#limitations) section.
|
|
1396
1423
|
|
|
1424
|
+
### In which order should I call `ready()` and `sync()`?
|
|
1425
|
+
|
|
1426
|
+
Always call [`ready()`](#ready) first, as early as possible after the app has started, and only then [`sync()`](#sync) or any other method that changes the bundle. `ready()` confirms that the current bundle works and stops the rollback timer. If you call `sync()` first, the `readyTimeout` keeps running while the next bundle is being downloaded, which can roll back a bundle that actually works.
|
|
1427
|
+
|
|
1397
1428
|
### How does the rollback mechanism work?
|
|
1398
1429
|
|
|
1399
1430
|
If the `readyTimeout` configuration option is set, the plugin waits for the app to call the [`ready()`](#ready) method after a new bundle has been applied. If the method is not called within the configured timeout, the plugin assumes the bundle is faulty and resets the app to the default bundle. It is strongly recommended to configure `readyTimeout` (e.g. `10000` ms). Additionally, with the `autoBlockRolledBackBundles` option enabled, bundles that caused a rollback are automatically blocked and skipped in future sync operations.
|
|
1400
1431
|
|
|
1432
|
+
### Why does my app hang after calling `reload()`?
|
|
1433
|
+
|
|
1434
|
+
If your app shows a blank or loading screen after calling [`reload()`](#reload) but works after a force quit, the new bundle was most likely applied correctly. You can verify this by logging the [current bundle](#check-which-bundle-is-running) at app start.
|
|
1435
|
+
|
|
1436
|
+
`reload()` reloads the web view without restarting the native process. Resources of the web layer that hold an exclusive lock are therefore not released automatically and can block the new bundle from starting. A force quit starts a new process and releases these resources, which is why the update seems to be applied only after a restart.
|
|
1437
|
+
|
|
1438
|
+
The most common cause is IndexedDB. The Firebase JS SDK, for example, holds an IndexedDB lease as long as Firestore offline persistence is enabled. Terminate the client before reloading the app:
|
|
1439
|
+
|
|
1440
|
+
```typescript
|
|
1441
|
+
import { getFirestore, terminate } from 'firebase/firestore';
|
|
1442
|
+
|
|
1443
|
+
await terminate(getFirestore());
|
|
1444
|
+
await LiveUpdate.reload();
|
|
1445
|
+
```
|
|
1446
|
+
|
|
1447
|
+
Keep in mind that offline persistence may be active even if you try to exclude web views, because guards that detect the browser by user agent usually also match the `WKWebView` on iOS. On Android, the problem is less likely to occur because Chromium recovers from a stale lease.
|
|
1448
|
+
|
|
1449
|
+
Other candidates are WebSockets, Web Locks and service workers. If you cannot release these resources, apply the new bundle on the next app start instead of reloading the app.
|
|
1450
|
+
|
|
1401
1451
|
## Related Plugins
|
|
1402
1452
|
|
|
1403
1453
|
- [App Update](https://capawesome.io/docs/sdks/capacitor/app-update/): Assist users with native app updates, which are required for changes that are not binary-compatible.
|
|
@@ -104,6 +104,7 @@ public class LiveUpdate {
|
|
|
104
104
|
private final SharedPreferences.Editor webViewSettingsEditor;
|
|
105
105
|
|
|
106
106
|
private final String bundlesDirectory = "_capacitor_live_update_bundles"; // DO NOT CHANGE!
|
|
107
|
+
private final String downloadsDirectory = "capawesome_capacitor_live_update_downloads";
|
|
107
108
|
private final Handler rollbackHandler = new Handler(Looper.getMainLooper());
|
|
108
109
|
private final String manifestFileName = "capawesome-live-update-manifest.json"; // DO NOT CHANGE!
|
|
109
110
|
|
|
@@ -125,6 +126,9 @@ public class LiveUpdate {
|
|
|
125
126
|
// Set the device ID on the HTTP client (after any potential config reset)
|
|
126
127
|
this.httpClient.setDeviceId(getDeviceId());
|
|
127
128
|
|
|
129
|
+
// Delete the leftovers of downloads that were interrupted by a process kill
|
|
130
|
+
tryDeleteDownloadsDirectory();
|
|
131
|
+
|
|
128
132
|
// Start the rollback timer to rollback to the default bundle
|
|
129
133
|
// if the app is not ready after a certain time
|
|
130
134
|
startRollbackTimer();
|
|
@@ -536,7 +540,10 @@ public class LiveUpdate {
|
|
|
536
540
|
|
|
537
541
|
// Move the bundle directory to the bundles directory
|
|
538
542
|
File bundleDirectory = buildBundleDirectoryFor(bundleId);
|
|
539
|
-
indexHtmlFile.getParentFile().renameTo(bundleDirectory);
|
|
543
|
+
boolean moved = indexHtmlFile.getParentFile().renameTo(bundleDirectory);
|
|
544
|
+
if (!moved) {
|
|
545
|
+
throw new Exception(LiveUpdatePlugin.ERROR_BUNDLE_MOVE_FAILED);
|
|
546
|
+
}
|
|
540
547
|
}
|
|
541
548
|
|
|
542
549
|
private void addBundleOfTypeManifest(@NonNull String bundleId, @NonNull File directory) throws Exception {
|
|
@@ -545,7 +552,7 @@ public class LiveUpdate {
|
|
|
545
552
|
|
|
546
553
|
private void addBundleOfTypeZip(@NonNull String bundleId, @NonNull File zipFile) throws Exception {
|
|
547
554
|
// Unzip the file to the bundle directory
|
|
548
|
-
File unzippedDirectory =
|
|
555
|
+
File unzippedDirectory = unzipDownloadedBundle(zipFile);
|
|
549
556
|
// Add the bundle
|
|
550
557
|
addBundle(bundleId, unzippedDirectory);
|
|
551
558
|
}
|
|
@@ -558,14 +565,8 @@ public class LiveUpdate {
|
|
|
558
565
|
return new File(plugin.getContext().getFilesDir(), bundlesDirectory + "/" + bundleId);
|
|
559
566
|
}
|
|
560
567
|
|
|
561
|
-
private File
|
|
562
|
-
|
|
563
|
-
return new File(plugin.getContext().getCacheDir(), fileName);
|
|
564
|
-
}
|
|
565
|
-
|
|
566
|
-
private File buildTemporaryZipFile() {
|
|
567
|
-
String fileName = UUID.randomUUID().toString() + ".zip";
|
|
568
|
-
return new File(plugin.getContext().getCacheDir(), fileName);
|
|
568
|
+
private File buildDownloadsDirectory() {
|
|
569
|
+
return new File(plugin.getContext().getCacheDir(), downloadsDirectory);
|
|
569
570
|
}
|
|
570
571
|
|
|
571
572
|
private void copyCurrentBundleFile(@NonNull ManifestItem fileToCopy, @NonNull File destinationDirectory) throws IOException {
|
|
@@ -652,10 +653,10 @@ public class LiveUpdate {
|
|
|
652
653
|
}
|
|
653
654
|
}
|
|
654
655
|
|
|
655
|
-
private File
|
|
656
|
-
File
|
|
657
|
-
|
|
658
|
-
return
|
|
656
|
+
private File createTemporaryDownloadDirectory() {
|
|
657
|
+
File temporaryDirectory = new File(buildDownloadsDirectory(), UUID.randomUUID().toString());
|
|
658
|
+
temporaryDirectory.mkdirs();
|
|
659
|
+
return temporaryDirectory;
|
|
659
660
|
}
|
|
660
661
|
|
|
661
662
|
private void deleteBundleById(@NonNull String bundleId) {
|
|
@@ -681,6 +682,23 @@ public class LiveUpdate {
|
|
|
681
682
|
file.delete();
|
|
682
683
|
}
|
|
683
684
|
|
|
685
|
+
@NonNull
|
|
686
|
+
private EmptyCallback deleteTemporaryDirectoryOnCompletion(@NonNull File temporaryDirectory, @NonNull EmptyCallback callback) {
|
|
687
|
+
return new EmptyCallback() {
|
|
688
|
+
@Override
|
|
689
|
+
public void success() {
|
|
690
|
+
deleteFileRecursively(temporaryDirectory);
|
|
691
|
+
callback.success();
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
@Override
|
|
695
|
+
public void error(@NonNull Exception exception) {
|
|
696
|
+
deleteFileRecursively(temporaryDirectory);
|
|
697
|
+
callback.error(exception);
|
|
698
|
+
}
|
|
699
|
+
};
|
|
700
|
+
}
|
|
701
|
+
|
|
684
702
|
private void deleteUnusedBundles() {
|
|
685
703
|
String[] bundleIds = getDownloadedBundleIds();
|
|
686
704
|
for (String bundleId : bundleIds) {
|
|
@@ -851,10 +869,10 @@ public class LiveUpdate {
|
|
|
851
869
|
@NonNull String downloadUrl,
|
|
852
870
|
@NonNull EmptyCallback completionCallback
|
|
853
871
|
) {
|
|
872
|
+
// Create a temporary directory that is deleted once the download completed or failed
|
|
873
|
+
File temporaryDirectory = createTemporaryDownloadDirectory();
|
|
874
|
+
EmptyCallback callback = deleteTemporaryDirectoryOnCompletion(temporaryDirectory, completionCallback);
|
|
854
875
|
try {
|
|
855
|
-
// Create a temporary directory
|
|
856
|
-
File temporaryDirectory = createTemporaryDirectory();
|
|
857
|
-
|
|
858
876
|
// Download the latest manifest
|
|
859
877
|
downloadBundleFile(
|
|
860
878
|
downloadUrl,
|
|
@@ -904,31 +922,31 @@ public class LiveUpdate {
|
|
|
904
922
|
try {
|
|
905
923
|
// Add the bundle
|
|
906
924
|
addBundleOfTypeManifest(bundleId, temporaryDirectory);
|
|
907
|
-
|
|
925
|
+
callback.success();
|
|
908
926
|
} catch (Exception e) {
|
|
909
|
-
|
|
927
|
+
callback.error(e);
|
|
910
928
|
}
|
|
911
929
|
}
|
|
912
930
|
|
|
913
931
|
@Override
|
|
914
932
|
public void error(@NonNull Exception exception) {
|
|
915
|
-
|
|
933
|
+
callback.error(exception);
|
|
916
934
|
}
|
|
917
935
|
}
|
|
918
936
|
);
|
|
919
937
|
} catch (Exception e) {
|
|
920
|
-
|
|
938
|
+
callback.error(e);
|
|
921
939
|
}
|
|
922
940
|
}
|
|
923
941
|
|
|
924
942
|
@Override
|
|
925
943
|
public void error(@NonNull Exception exception) {
|
|
926
|
-
|
|
944
|
+
callback.error(exception);
|
|
927
945
|
}
|
|
928
946
|
}
|
|
929
947
|
);
|
|
930
948
|
} catch (Exception e) {
|
|
931
|
-
|
|
949
|
+
callback.error(e);
|
|
932
950
|
}
|
|
933
951
|
}
|
|
934
952
|
|
|
@@ -939,39 +957,42 @@ public class LiveUpdate {
|
|
|
939
957
|
@NonNull String downloadUrl,
|
|
940
958
|
@NonNull EmptyCallback completionCallback
|
|
941
959
|
) {
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
960
|
+
// Create a temporary directory that is deleted once the download completed or failed
|
|
961
|
+
File temporaryDirectory = createTemporaryDownloadDirectory();
|
|
962
|
+
EmptyCallback callback = deleteTemporaryDirectoryOnCompletion(temporaryDirectory, completionCallback);
|
|
963
|
+
File zipFile = new File(temporaryDirectory, "bundle.zip");
|
|
964
|
+
try {
|
|
965
|
+
// Download the bundle
|
|
966
|
+
downloadAndVerifyFile(
|
|
967
|
+
downloadUrl,
|
|
968
|
+
zipFile,
|
|
969
|
+
checksum,
|
|
970
|
+
signature,
|
|
971
|
+
(downloadedBytes, totalBytes) -> {
|
|
972
|
+
DownloadBundleProgressEvent event = new DownloadBundleProgressEvent(bundleId, downloadedBytes, totalBytes);
|
|
973
|
+
notifyDownloadBundleProgressListeners(event);
|
|
974
|
+
},
|
|
975
|
+
new EmptyCallback() {
|
|
976
|
+
@Override
|
|
977
|
+
public void success() {
|
|
978
|
+
try {
|
|
979
|
+
// Add the bundle
|
|
980
|
+
addBundleOfTypeZip(bundleId, zipFile);
|
|
981
|
+
callback.success();
|
|
982
|
+
} catch (Exception e) {
|
|
983
|
+
callback.error(e);
|
|
984
|
+
}
|
|
964
985
|
}
|
|
965
|
-
}
|
|
966
986
|
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
completionCallback.error(exception);
|
|
987
|
+
@Override
|
|
988
|
+
public void error(@NonNull Exception exception) {
|
|
989
|
+
callback.error(exception);
|
|
990
|
+
}
|
|
972
991
|
}
|
|
973
|
-
|
|
974
|
-
)
|
|
992
|
+
);
|
|
993
|
+
} catch (Exception e) {
|
|
994
|
+
callback.error(e);
|
|
995
|
+
}
|
|
975
996
|
}
|
|
976
997
|
|
|
977
998
|
private void fetchLatestBundleInternal(
|
|
@@ -1437,8 +1458,12 @@ public class LiveUpdate {
|
|
|
1437
1458
|
}
|
|
1438
1459
|
}
|
|
1439
1460
|
|
|
1440
|
-
private
|
|
1441
|
-
|
|
1461
|
+
private void tryDeleteDownloadsDirectory() {
|
|
1462
|
+
deleteFileRecursively(buildDownloadsDirectory());
|
|
1463
|
+
}
|
|
1464
|
+
|
|
1465
|
+
private File unzipDownloadedBundle(@NonNull File zipFile) throws IOException {
|
|
1466
|
+
File destination = new File(zipFile.getParentFile(), "bundle");
|
|
1442
1467
|
String destinationPath = destination.getPath();
|
|
1443
1468
|
ZipFile zip = new ZipFile(zipFile);
|
|
1444
1469
|
// Clear stored Unix permissions to prevent EACCES errors on newer Android versions
|
package/android/src/main/java/io/capawesome/capacitorjs/plugins/liveupdate/LiveUpdatePlugin.java
CHANGED
|
@@ -37,12 +37,13 @@ import io.capawesome.capacitorjs.plugins.liveupdate.interfaces.Result;
|
|
|
37
37
|
public class LiveUpdatePlugin extends Plugin {
|
|
38
38
|
|
|
39
39
|
public static final String TAG = "LiveUpdate";
|
|
40
|
-
public static final String VERSION = "8.4.
|
|
40
|
+
public static final String VERSION = "8.4.3";
|
|
41
41
|
public static final String SHARED_PREFERENCES_NAME = "CapawesomeLiveUpdate"; // DO NOT CHANGE
|
|
42
42
|
public static final String ERROR_APP_ID_MISSING = "appId must be configured.";
|
|
43
43
|
public static final String ERROR_BUNDLE_EXISTS = "bundle already exists.";
|
|
44
44
|
public static final String ERROR_BUNDLE_ID_MISSING = "bundleId must be provided.";
|
|
45
45
|
public static final String ERROR_BUNDLE_INDEX_HTML_MISSING = "The bundle does not contain an index.html file.";
|
|
46
|
+
public static final String ERROR_BUNDLE_MOVE_FAILED = "Bundle could not be moved.";
|
|
46
47
|
public static final String ERROR_BUNDLE_NOT_FOUND = "bundle not found.";
|
|
47
48
|
public static final String ERROR_CHECKSUM_CALCULATION_FAILED = "Failed to calculate checksum.";
|
|
48
49
|
public static final String ERROR_CHECKSUM_MISMATCH = "Checksum mismatch.";
|
package/dist/docs.json
CHANGED
|
@@ -333,7 +333,7 @@
|
|
|
333
333
|
"text": "5.0.0"
|
|
334
334
|
}
|
|
335
335
|
],
|
|
336
|
-
"docs": "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\nto prevent the app from being reset to the default bundle.\n\nOnly available on Android and iOS.",
|
|
336
|
+
"docs": "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\nto prevent the app from being reset to the default bundle.\nIt must always be called before `sync(...)` or any other method that changes the bundle.\n\nOnly available on Android and iOS.",
|
|
337
337
|
"complexTypes": [
|
|
338
338
|
"ReadyResult"
|
|
339
339
|
],
|
|
@@ -350,7 +350,7 @@
|
|
|
350
350
|
"text": "5.0.0"
|
|
351
351
|
}
|
|
352
352
|
],
|
|
353
|
-
"docs": "Reload the app to apply the new bundle.\n\nOnly available on Android and iOS.",
|
|
353
|
+
"docs": "Reload the app to apply the new bundle.\n\nThis method reloads the web view only, the native process is **not** restarted.\nResources of the web layer that hold an exclusive lock (e.g. IndexedDB or WebSockets)\nare therefore not released automatically and may prevent the new bundle from starting.\nRelease these resources before calling this method or apply the new bundle\non the next app start instead.\n\n**Attention**: The in-memory state of the app (e.g. unsaved user input) is lost.\n\nOnly available on Android and iOS.",
|
|
354
354
|
"complexTypes": [],
|
|
355
355
|
"slug": "reload"
|
|
356
356
|
},
|
|
@@ -284,6 +284,7 @@ export interface LiveUpdatePlugin {
|
|
|
284
284
|
*
|
|
285
285
|
* **Attention**: This method should be called as soon as the app is ready to use
|
|
286
286
|
* to prevent the app from being reset to the default bundle.
|
|
287
|
+
* It must always be called before `sync(...)` or any other method that changes the bundle.
|
|
287
288
|
*
|
|
288
289
|
* Only available on Android and iOS.
|
|
289
290
|
*
|
|
@@ -293,6 +294,14 @@ export interface LiveUpdatePlugin {
|
|
|
293
294
|
/**
|
|
294
295
|
* Reload the app to apply the new bundle.
|
|
295
296
|
*
|
|
297
|
+
* This method reloads the web view only, the native process is **not** restarted.
|
|
298
|
+
* Resources of the web layer that hold an exclusive lock (e.g. IndexedDB or WebSockets)
|
|
299
|
+
* are therefore not released automatically and may prevent the new bundle from starting.
|
|
300
|
+
* Release these resources before calling this method or apply the new bundle
|
|
301
|
+
* on the next app start instead.
|
|
302
|
+
*
|
|
303
|
+
* **Attention**: The in-memory state of the app (e.g. unsaved user input) is lost.
|
|
304
|
+
*
|
|
296
305
|
* Only available on Android and iOS.
|
|
297
306
|
*
|
|
298
307
|
* @since 5.0.0
|
|
@@ -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 * This can be overridden by `setChannel()`, the `channel` parameter of `sync()`,\n * or the native channel configuration\n * (`CapawesomeLiveUpdateDefaultChannel` in `Info.plist` on iOS or `capawesome_live_update_default_channel`\n * in `strings.xml` on Android).\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 channels from [Capawesome Cloud](https://capawesome.io/cloud/).\n *\n * This is primarily intended for development and QA purposes.\n * It allows you to retrieve a list of available channels so you can\n * dynamically switch between them using `setChannel(...)`.\n *\n * **Attention**: Only works for apps with public channels enabled.\n * If channels are private, they can still be set using `setChannel(...)`\n * but won't be returned by this method.\n *\n * Only available on Android and iOS.\n *\n * @since 8.2.0\n */\n fetchChannels(options?: FetchChannelsOptions): Promise<FetchChannelsResult>;\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 * The channel is resolved in the following order (highest priority first):\n * 1. `setChannel()` (SharedPreferences on Android / UserDefaults on iOS)\n * 2. Native config (`CapawesomeLiveUpdateDefaultChannel` in `Info.plist` on iOS or\n * `capawesome_live_update_default_channel` in `strings.xml` on Android)\n * 3. Capacitor config `defaultChannel`\n *\n * **Note**: The `channel` parameter of `sync()` takes the highest priority\n * but is not persisted and therefore not returned by this method.\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 8.2.0\n */\nexport interface FetchChannelsOptions {\n /**\n * The maximum number of channels to return.\n *\n * @since 8.2.0\n * @default 50\n */\n limit?: number;\n /**\n * The number of channels to skip.\n *\n * @since 8.2.0\n * @default 0\n */\n offset?: number;\n /**\n * The query to filter channels by name.\n *\n * @since 8.2.0\n */\n query?: string;\n}\n\n/**\n * @since 8.2.0\n */\nexport interface FetchChannelsResult {\n /**\n * The list of channels.\n *\n * @since 8.2.0\n */\n channels: Channel[];\n}\n\n/**\n * @since 8.2.0\n */\nexport interface Channel {\n /**\n * The unique identifier of the channel.\n *\n * @since 8.2.0\n */\n id: string;\n /**\n * The name of the channel.\n *\n * @since 8.2.0\n */\n name: string;\n}\n\n/**\n * @since 6.7.0\n */\nexport interface FetchLatestBundleOptions {\n /**\n * The preferred channel name from which the latest bundle should be fetched.\n *\n * This is the SDK preference and may be overridden by a forced channel assignment\n * configured in the Capawesome Cloud Console.\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 * On Capawesome Cloud, this is the ID of the app build artifact.\n *\n * If `null`, no bundle is available.\n *\n * @since 6.6.0\n */\n bundleId: string | null;\n /**\n * The name of the channel that the bundle is actually from.\n *\n * This is the resolved channel after applying any forced channel assignment\n * and may differ from the channel set by the Live Update SDK.\n *\n * @since 8.3.0\n */\n channel?: string;\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 preferred channel name from which the latest bundle should be fetched.\n *\n * This is the SDK preference and may be overridden by a forced channel assignment\n * configured in the Capawesome Cloud Console.\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 * This can be overridden by `setChannel()`, the `channel` parameter of `sync()`,\n * or the native channel configuration\n * (`CapawesomeLiveUpdateDefaultChannel` in `Info.plist` on iOS or `capawesome_live_update_default_channel`\n * in `strings.xml` on Android).\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 channels from [Capawesome Cloud](https://capawesome.io/cloud/).\n *\n * This is primarily intended for development and QA purposes.\n * It allows you to retrieve a list of available channels so you can\n * dynamically switch between them using `setChannel(...)`.\n *\n * **Attention**: Only works for apps with public channels enabled.\n * If channels are private, they can still be set using `setChannel(...)`\n * but won't be returned by this method.\n *\n * Only available on Android and iOS.\n *\n * @since 8.2.0\n */\n fetchChannels(options?: FetchChannelsOptions): Promise<FetchChannelsResult>;\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 * The channel is resolved in the following order (highest priority first):\n * 1. `setChannel()` (SharedPreferences on Android / UserDefaults on iOS)\n * 2. Native config (`CapawesomeLiveUpdateDefaultChannel` in `Info.plist` on iOS or\n * `capawesome_live_update_default_channel` in `strings.xml` on Android)\n * 3. Capacitor config `defaultChannel`\n *\n * **Note**: The `channel` parameter of `sync()` takes the highest priority\n * but is not persisted and therefore not returned by this method.\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 * It must always be called before `sync(...)` or any other method that changes the 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 * This method reloads the web view only, the native process is **not** restarted.\n * Resources of the web layer that hold an exclusive lock (e.g. IndexedDB or WebSockets)\n * are therefore not released automatically and may prevent the new bundle from starting.\n * Release these resources before calling this method or apply the new bundle\n * on the next app start instead.\n *\n * **Attention**: The in-memory state of the app (e.g. unsaved user input) is lost.\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 8.2.0\n */\nexport interface FetchChannelsOptions {\n /**\n * The maximum number of channels to return.\n *\n * @since 8.2.0\n * @default 50\n */\n limit?: number;\n /**\n * The number of channels to skip.\n *\n * @since 8.2.0\n * @default 0\n */\n offset?: number;\n /**\n * The query to filter channels by name.\n *\n * @since 8.2.0\n */\n query?: string;\n}\n\n/**\n * @since 8.2.0\n */\nexport interface FetchChannelsResult {\n /**\n * The list of channels.\n *\n * @since 8.2.0\n */\n channels: Channel[];\n}\n\n/**\n * @since 8.2.0\n */\nexport interface Channel {\n /**\n * The unique identifier of the channel.\n *\n * @since 8.2.0\n */\n id: string;\n /**\n * The name of the channel.\n *\n * @since 8.2.0\n */\n name: string;\n}\n\n/**\n * @since 6.7.0\n */\nexport interface FetchLatestBundleOptions {\n /**\n * The preferred channel name from which the latest bundle should be fetched.\n *\n * This is the SDK preference and may be overridden by a forced channel assignment\n * configured in the Capawesome Cloud Console.\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 * On Capawesome Cloud, this is the ID of the app build artifact.\n *\n * If `null`, no bundle is available.\n *\n * @since 6.6.0\n */\n bundleId: string | null;\n /**\n * The name of the channel that the bundle is actually from.\n *\n * This is the resolved channel after applying any forced channel assignment\n * and may differ from the channel set by the Live Update SDK.\n *\n * @since 8.3.0\n */\n channel?: string;\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 preferred channel name from which the latest bundle should be fetched.\n *\n * This is the SDK preference and may be overridden by a forced channel assignment\n * configured in the Capawesome Cloud Console.\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"]}
|
|
@@ -13,6 +13,7 @@ import CommonCrypto
|
|
|
13
13
|
private let config: LiveUpdateConfig
|
|
14
14
|
private let defaultWebAssetDir = "public" // DO NOT CHANGE! (See https://dub.sh/Buvz4yj)
|
|
15
15
|
private let defaultServerPathKey = "serverBasePath" // DO NOT CHANGE! (See https://dub.sh/ceDl0zT)
|
|
16
|
+
private let downloadsDirectory = "capawesome_capacitor_live_update_downloads"
|
|
16
17
|
private let httpClient: LiveUpdateHttpClient
|
|
17
18
|
private let libraryDirectoryUrl = FileManager.default.urls(for: .libraryDirectory, in: .userDomainMask).first!
|
|
18
19
|
private let manifestFileName = "capawesome-live-update-manifest.json" // DO NOT CHANGE!
|
|
@@ -37,6 +38,9 @@ import CommonCrypto
|
|
|
37
38
|
// Set the device ID on the HTTP client (after any potential config reset)
|
|
38
39
|
self.httpClient.setDeviceId(getDeviceId())
|
|
39
40
|
|
|
41
|
+
// Delete the leftovers of downloads that were interrupted by a process kill
|
|
42
|
+
tryDeleteDownloadsDirectory()
|
|
43
|
+
|
|
40
44
|
// Start the rollback timer to rollback to the default bundle
|
|
41
45
|
// if the app is not ready after a certain time
|
|
42
46
|
startRollbackTimer()
|
|
@@ -355,7 +359,7 @@ import CommonCrypto
|
|
|
355
359
|
|
|
356
360
|
private func addBundleOfTypeZip(bundleId: String, zipFile: URL) async throws {
|
|
357
361
|
// Unzip the bundle
|
|
358
|
-
let unzippedDirectory = try self.
|
|
362
|
+
let unzippedDirectory = try self.unzipDownloadedBundle(zipFile: zipFile)
|
|
359
363
|
// Add the bundle
|
|
360
364
|
try self.addBundle(bundleId: bundleId, directory: unzippedDirectory)
|
|
361
365
|
}
|
|
@@ -379,6 +383,10 @@ import CommonCrypto
|
|
|
379
383
|
return url
|
|
380
384
|
}
|
|
381
385
|
|
|
386
|
+
private func buildDownloadsDirectoryUrl() -> URL {
|
|
387
|
+
return cachesDirectoryUrl.appendingPathComponent(downloadsDirectory)
|
|
388
|
+
}
|
|
389
|
+
|
|
382
390
|
private func copyCurrentBundleFile(fileToCopy: ManifestItem, toDirectory: URL) throws {
|
|
383
391
|
let currentBundleId = getCurrentBundleId()
|
|
384
392
|
let destination = toDirectory.appendingPathComponent(fileToCopy.href)
|
|
@@ -428,8 +436,8 @@ import CommonCrypto
|
|
|
428
436
|
}
|
|
429
437
|
}
|
|
430
438
|
|
|
431
|
-
private func
|
|
432
|
-
let temporaryDirectory =
|
|
439
|
+
private func createTemporaryDownloadDirectory() throws -> URL {
|
|
440
|
+
let temporaryDirectory = buildDownloadsDirectoryUrl().appendingPathComponent(UUID().uuidString)
|
|
433
441
|
try FileManager.default.createDirectory(at: temporaryDirectory, withIntermediateDirectories: true, attributes: nil)
|
|
434
442
|
return temporaryDirectory
|
|
435
443
|
}
|
|
@@ -537,8 +545,9 @@ import CommonCrypto
|
|
|
537
545
|
}
|
|
538
546
|
|
|
539
547
|
private func downloadBundleOfTypeManifest(bundleId: String, url: String) async throws {
|
|
540
|
-
// Create a temporary directory
|
|
541
|
-
let temporaryDirectory = try
|
|
548
|
+
// Create a temporary directory that is deleted once the download completed or failed
|
|
549
|
+
let temporaryDirectory = try createTemporaryDownloadDirectory()
|
|
550
|
+
defer { tryDeleteDirectory(temporaryDirectory) }
|
|
542
551
|
// Download the latest manifest
|
|
543
552
|
let latestManifestFile = try await downloadBundleFile(baseUrl: url, href: manifestFileName, directory: temporaryDirectory, callback: nil)
|
|
544
553
|
let latestManifest = try loadManifest(file: latestManifestFile)
|
|
@@ -569,15 +578,17 @@ import CommonCrypto
|
|
|
569
578
|
}
|
|
570
579
|
|
|
571
580
|
private func downloadBundleOfTypeZip(bundleId: String, checksum: String?, signature: String?, url: String) async throws {
|
|
572
|
-
|
|
573
|
-
let
|
|
581
|
+
// Create a temporary directory that is deleted once the download completed or failed
|
|
582
|
+
let temporaryDirectory = try createTemporaryDownloadDirectory()
|
|
583
|
+
defer { tryDeleteDirectory(temporaryDirectory) }
|
|
584
|
+
let zipFile = temporaryDirectory.appendingPathComponent("bundle.zip")
|
|
574
585
|
// Download the bundle
|
|
575
|
-
try await downloadAndVerifyFile(url: url, file:
|
|
586
|
+
try await downloadAndVerifyFile(url: url, file: zipFile, checksum: checksum, signature: signature, callback: { progress in
|
|
576
587
|
let event = DownloadBundleProgressEvent(bundleId: bundleId, downloadedBytes: progress.completedUnitCount, totalBytes: progress.totalUnitCount)
|
|
577
588
|
self.notifyDownloadBundleProgressListeners(event)
|
|
578
589
|
})
|
|
579
590
|
// Add the bundle
|
|
580
|
-
try await addBundleOfTypeZip(bundleId: bundleId, zipFile:
|
|
591
|
+
try await addBundleOfTypeZip(bundleId: bundleId, zipFile: zipFile)
|
|
581
592
|
}
|
|
582
593
|
|
|
583
594
|
private func fetchLatestBundle(_ options: FetchLatestBundleOptions) async throws -> GetLatestBundleResponse? {
|
|
@@ -963,8 +974,23 @@ import CommonCrypto
|
|
|
963
974
|
}
|
|
964
975
|
}
|
|
965
976
|
|
|
966
|
-
private func
|
|
967
|
-
|
|
977
|
+
private func tryDeleteDirectory(_ url: URL) {
|
|
978
|
+
guard FileManager.default.fileExists(atPath: url.path) else {
|
|
979
|
+
return
|
|
980
|
+
}
|
|
981
|
+
do {
|
|
982
|
+
try FileManager.default.removeItem(at: url)
|
|
983
|
+
} catch {
|
|
984
|
+
CAPLog.print("[", LiveUpdatePlugin.tag, "] ", "Failed to delete directory: \(url.path)")
|
|
985
|
+
}
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
private func tryDeleteDownloadsDirectory() {
|
|
989
|
+
tryDeleteDirectory(buildDownloadsDirectoryUrl())
|
|
990
|
+
}
|
|
991
|
+
|
|
992
|
+
private func unzipDownloadedBundle(zipFile: URL) throws -> URL {
|
|
993
|
+
let destinationDirectory = zipFile.deletingLastPathComponent().appendingPathComponent("bundle")
|
|
968
994
|
try FileManager.default.createDirectory(at: destinationDirectory, withIntermediateDirectories: true, attributes: nil)
|
|
969
995
|
try FileManager.default.unzipItem(at: zipFile, to: destinationDirectory)
|
|
970
996
|
return destinationDirectory
|
|
@@ -8,7 +8,7 @@ import Capacitor
|
|
|
8
8
|
@objc(LiveUpdatePlugin)
|
|
9
9
|
public class LiveUpdatePlugin: CAPPlugin, CAPBridgedPlugin {
|
|
10
10
|
public static let tag = "LiveUpdate"
|
|
11
|
-
public static let version = "8.4.
|
|
11
|
+
public static let version = "8.4.3"
|
|
12
12
|
public static let userDefaultsPrefix = "CapawesomeLiveUpdate" // DO NOT CHANGE
|
|
13
13
|
|
|
14
14
|
public let identifier = "LiveUpdatePlugin"
|
package/package.json
CHANGED