@capawesome/capacitor-live-update 6.7.1 → 6.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -6
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/liveupdate/LiveUpdate.java +20 -9
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/liveupdate/LiveUpdatePlugin.java +3 -2
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/liveupdate/classes/api/GetLatestBundleResponse.java +18 -0
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/liveupdate/classes/options/DownloadBundleOptions.java +16 -1
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/liveupdate/classes/results/FetchLatestBundleResult.java +21 -1
- package/dist/docs.json +36 -4
- package/dist/esm/definitions.d.ts +30 -3
- package/dist/esm/definitions.js.map +1 -1
- package/ios/Plugin/Classes/Options/DownloadBundleOptions.swift +7 -1
- package/ios/Plugin/Classes/Results/FetchLatestBundle.swift +11 -1
- package/ios/Plugin/LiveUpdate.swift +31 -22
- package/ios/Plugin/LiveUpdatePlugin.swift +3 -2
- package/ios/Plugin/LiveUpdatePreferences.swift +20 -2
- package/ios/Plugin/Protocols/Api/GetLatestBundleResponse.swift +2 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -651,17 +651,20 @@ Only available on Android and iOS.
|
|
|
651
651
|
| ------------------ | -------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------ | ----- |
|
|
652
652
|
| **`artifactType`** | <code>'manifest' \| 'zip'</code> | The artifact type of the bundle. | <code>'zip'</code> | 6.6.0 |
|
|
653
653
|
| **`bundleId`** | <code>string</code> | The unique identifier of the bundle. | | 5.0.0 |
|
|
654
|
-
| **`checksum`** | <code>string</code> | The checksum of the bundle to verify the integrity of the
|
|
654
|
+
| **`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. | | 6.1.0 |
|
|
655
|
+
| **`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. | | 6.8.0 |
|
|
655
656
|
| **`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 must return a `X-Checksum` header with the SHA-256 hash in base64 format. To **verify the signature** of the file, the server must return a `X-Signature` header with the signed SHA-256 hash in base64 format. | | 5.0.0 |
|
|
656
657
|
|
|
657
658
|
|
|
658
659
|
#### FetchLatestBundleResult
|
|
659
660
|
|
|
660
|
-
| Prop | Type | Description
|
|
661
|
-
| ------------------ | -------------------------------- |
|
|
662
|
-
| **`artifactType`** | <code>'manifest' \| 'zip'</code> | The artifact type of the bundle.
|
|
663
|
-
| **`bundleId`** | <code>string \| null</code> | The unique identifier of the latest bundle. If `null`, no bundle is available.
|
|
664
|
-
| **`
|
|
661
|
+
| Prop | Type | Description | Since |
|
|
662
|
+
| ------------------ | -------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----- |
|
|
663
|
+
| **`artifactType`** | <code>'manifest' \| 'zip'</code> | The artifact type of the bundle. | 6.7.0 |
|
|
664
|
+
| **`bundleId`** | <code>string \| null</code> | The unique identifier of the latest bundle. If `null`, no bundle is available. | 6.6.0 |
|
|
665
|
+
| **`checksum`** | <code>string</code> | The checksum of the latest bundle if the bundle is self-hosted. If the bundle is hosted on Capawesome Cloud, the checksum will be returned as response header when downloading the bundle. | 6.8.0 |
|
|
666
|
+
| **`downloadUrl`** | <code>string</code> | The URL of the latest bundle to download. Pass this URL to the `downloadBundle(...)` method to download the bundle. | 6.7.0 |
|
|
667
|
+
| **`signature`** | <code>string</code> | The signature of the latest bundle if the bundle is self-hosted. If the bundle is hosted on Capawesome Cloud, the signature will be returned as response header when downloading the bundle. | 6.8.0 |
|
|
665
668
|
|
|
666
669
|
|
|
667
670
|
#### FetchLatestBundleOptions
|
|
@@ -104,6 +104,7 @@ public class LiveUpdate {
|
|
|
104
104
|
|
|
105
105
|
if (config.getEnabled()) {
|
|
106
106
|
if (wasUpdated() && config.getResetOnUpdate()) {
|
|
107
|
+
Logger.debug(LiveUpdatePlugin.TAG, "App was updated. Resetting to default bundle.");
|
|
107
108
|
reset();
|
|
108
109
|
} else {
|
|
109
110
|
startRollbackTimer();
|
|
@@ -129,6 +130,7 @@ public class LiveUpdate {
|
|
|
129
130
|
ArtifactType artifactType = options.getArtifactType();
|
|
130
131
|
String bundleId = options.getBundleId();
|
|
131
132
|
String checksum = options.getChecksum();
|
|
133
|
+
String signature = options.getSignature();
|
|
132
134
|
String url = options.getUrl();
|
|
133
135
|
|
|
134
136
|
// Check if the bundle already exists
|
|
@@ -142,7 +144,7 @@ public class LiveUpdate {
|
|
|
142
144
|
if (artifactType == ArtifactType.MANIFEST) {
|
|
143
145
|
downloadBundleOfTypeManifest(bundleId, url);
|
|
144
146
|
} else {
|
|
145
|
-
downloadBundleOfTypeZip(bundleId, url, checksum);
|
|
147
|
+
downloadBundleOfTypeZip(bundleId, url, checksum, signature);
|
|
146
148
|
}
|
|
147
149
|
callback.success();
|
|
148
150
|
}
|
|
@@ -151,8 +153,10 @@ public class LiveUpdate {
|
|
|
151
153
|
GetLatestBundleResponse response = fetchLatestBundle(options);
|
|
152
154
|
ArtifactType artifactType = response == null ? null : response.getArtifactType();
|
|
153
155
|
String bundleId = response == null ? null : response.getBundleId();
|
|
156
|
+
String checksum = response == null ? null : response.getChecksum();
|
|
154
157
|
String downloadUrl = response == null ? null : response.getUrl();
|
|
155
|
-
|
|
158
|
+
String signature = response == null ? null : response.getSignature();
|
|
159
|
+
FetchLatestBundleResult result = new FetchLatestBundleResult(artifactType, bundleId, checksum, downloadUrl, signature);
|
|
156
160
|
callback.success(result);
|
|
157
161
|
}
|
|
158
162
|
|
|
@@ -295,6 +299,8 @@ public class LiveUpdate {
|
|
|
295
299
|
return;
|
|
296
300
|
}
|
|
297
301
|
ArtifactType artifactType = response.getArtifactType();
|
|
302
|
+
String checksum = response.getChecksum();
|
|
303
|
+
String signature = response.getSignature();
|
|
298
304
|
String latestBundleId = response.getBundleId();
|
|
299
305
|
String url = response.getUrl();
|
|
300
306
|
// Check if the bundle already exists
|
|
@@ -314,7 +320,7 @@ public class LiveUpdate {
|
|
|
314
320
|
if (artifactType == ArtifactType.MANIFEST) {
|
|
315
321
|
downloadBundleOfTypeManifest(latestBundleId, url);
|
|
316
322
|
} else {
|
|
317
|
-
downloadBundleOfTypeZip(latestBundleId, url,
|
|
323
|
+
downloadBundleOfTypeZip(latestBundleId, url, checksum, signature);
|
|
318
324
|
}
|
|
319
325
|
// Set the next bundle
|
|
320
326
|
setNextBundle(latestBundleId);
|
|
@@ -474,14 +480,15 @@ public class LiveUpdate {
|
|
|
474
480
|
}
|
|
475
481
|
}
|
|
476
482
|
|
|
477
|
-
private void downloadAndVerifyFile(@NonNull String url, @NonNull File file, @Nullable String checksum
|
|
483
|
+
private void downloadAndVerifyFile(@NonNull String url, @NonNull File file, @Nullable String checksum, @Nullable String signature)
|
|
484
|
+
throws Exception {
|
|
478
485
|
Response response = httpClient.execute(url);
|
|
479
486
|
ResponseBody responseBody = response.body();
|
|
480
487
|
if (response.isSuccessful()) {
|
|
481
488
|
LiveUpdateHttpClient.writeResponseBodyToFile(responseBody, file);
|
|
482
489
|
// Verify the file
|
|
483
490
|
checksum = checksum == null ? LiveUpdateHttpClient.getChecksumFromResponse(response) : checksum;
|
|
484
|
-
|
|
491
|
+
signature = signature == null ? LiveUpdateHttpClient.getSignatureFromResponse(response) : signature;
|
|
485
492
|
verifyFile(file, checksum, signature);
|
|
486
493
|
} else {
|
|
487
494
|
Exception exception = new Exception(responseBody.string());
|
|
@@ -497,7 +504,7 @@ public class LiveUpdate {
|
|
|
497
504
|
|
|
498
505
|
File destinationFile = new File(destinationDirectory, href);
|
|
499
506
|
destinationFile.getParentFile().mkdirs();
|
|
500
|
-
downloadAndVerifyFile(url, destinationFile, null);
|
|
507
|
+
downloadAndVerifyFile(url, destinationFile, null, null);
|
|
501
508
|
return destinationFile;
|
|
502
509
|
}
|
|
503
510
|
|
|
@@ -579,11 +586,15 @@ public class LiveUpdate {
|
|
|
579
586
|
addBundleOfTypeManifest(bundleId, temporaryDirectory);
|
|
580
587
|
}
|
|
581
588
|
|
|
582
|
-
private void downloadBundleOfTypeZip(
|
|
583
|
-
|
|
589
|
+
private void downloadBundleOfTypeZip(
|
|
590
|
+
@NonNull String bundleId,
|
|
591
|
+
@NonNull String downloadUrl,
|
|
592
|
+
@Nullable String checksum,
|
|
593
|
+
@Nullable String signature
|
|
594
|
+
) throws Exception {
|
|
584
595
|
File file = buildTemporaryZipFile();
|
|
585
596
|
// Download the bundle
|
|
586
|
-
downloadAndVerifyFile(downloadUrl, file, checksum);
|
|
597
|
+
downloadAndVerifyFile(downloadUrl, file, checksum, signature);
|
|
587
598
|
// Add the bundle
|
|
588
599
|
addBundleOfTypeZip(bundleId, file);
|
|
589
600
|
// Delete the temporary file
|
package/android/src/main/java/io/capawesome/capacitorjs/plugins/liveupdate/LiveUpdatePlugin.java
CHANGED
|
@@ -24,7 +24,7 @@ import io.capawesome.capacitorjs.plugins.liveupdate.interfaces.Result;
|
|
|
24
24
|
public class LiveUpdatePlugin extends Plugin {
|
|
25
25
|
|
|
26
26
|
public static final String TAG = "LiveUpdate";
|
|
27
|
-
public static final String VERSION = "6.
|
|
27
|
+
public static final String VERSION = "6.8.0";
|
|
28
28
|
public static final String SHARED_PREFERENCES_NAME = "CapawesomeLiveUpdate"; // DO NOT CHANGE
|
|
29
29
|
public static final String ERROR_APP_ID_MISSING = "appId must be configured.";
|
|
30
30
|
public static final String ERROR_BUNDLE_EXISTS = "bundle already exists.";
|
|
@@ -98,13 +98,14 @@ public class LiveUpdatePlugin extends Plugin {
|
|
|
98
98
|
return;
|
|
99
99
|
}
|
|
100
100
|
String checksum = call.getString("checksum");
|
|
101
|
+
String signature = call.getString("signature");
|
|
101
102
|
String url = call.getString("url");
|
|
102
103
|
if (url == null) {
|
|
103
104
|
call.reject(ERROR_URL_MISSING);
|
|
104
105
|
return;
|
|
105
106
|
}
|
|
106
107
|
|
|
107
|
-
DownloadBundleOptions options = new DownloadBundleOptions(artifactType, bundleId, checksum, url);
|
|
108
|
+
DownloadBundleOptions options = new DownloadBundleOptions(artifactType, bundleId, checksum, signature, url);
|
|
108
109
|
EmptyCallback callback = new EmptyCallback() {
|
|
109
110
|
@Override
|
|
110
111
|
public void success() {
|
|
@@ -16,6 +16,12 @@ public class GetLatestBundleResponse {
|
|
|
16
16
|
@NonNull
|
|
17
17
|
private String bundleId;
|
|
18
18
|
|
|
19
|
+
@Nullable
|
|
20
|
+
private String checksum;
|
|
21
|
+
|
|
22
|
+
@Nullable
|
|
23
|
+
private String signature;
|
|
24
|
+
|
|
19
25
|
@NonNull
|
|
20
26
|
private String url;
|
|
21
27
|
|
|
@@ -27,6 +33,8 @@ public class GetLatestBundleResponse {
|
|
|
27
33
|
this.artifactType = ArtifactType.ZIP;
|
|
28
34
|
}
|
|
29
35
|
this.bundleId = responseJson.optString("bundleId");
|
|
36
|
+
this.checksum = responseJson.optString("checksum");
|
|
37
|
+
this.signature = responseJson.optString("signature");
|
|
30
38
|
this.url = responseJson.optString("url");
|
|
31
39
|
}
|
|
32
40
|
|
|
@@ -40,6 +48,16 @@ public class GetLatestBundleResponse {
|
|
|
40
48
|
return bundleId;
|
|
41
49
|
}
|
|
42
50
|
|
|
51
|
+
@Nullable
|
|
52
|
+
public String getChecksum() {
|
|
53
|
+
return checksum;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
@Nullable
|
|
57
|
+
public String getSignature() {
|
|
58
|
+
return signature;
|
|
59
|
+
}
|
|
60
|
+
|
|
43
61
|
@NonNull
|
|
44
62
|
public String getUrl() {
|
|
45
63
|
return url;
|
|
@@ -15,10 +15,19 @@ public class DownloadBundleOptions {
|
|
|
15
15
|
@Nullable
|
|
16
16
|
private String checksum;
|
|
17
17
|
|
|
18
|
+
@Nullable
|
|
19
|
+
private String signature;
|
|
20
|
+
|
|
18
21
|
@NonNull
|
|
19
22
|
private String url;
|
|
20
23
|
|
|
21
|
-
public DownloadBundleOptions(
|
|
24
|
+
public DownloadBundleOptions(
|
|
25
|
+
@NonNull String artifactType,
|
|
26
|
+
@NonNull String bundleId,
|
|
27
|
+
@Nullable String checksum,
|
|
28
|
+
@Nullable String signature,
|
|
29
|
+
@NonNull String url
|
|
30
|
+
) {
|
|
22
31
|
if (artifactType.equals("manifest")) {
|
|
23
32
|
this.artifactType = ArtifactType.MANIFEST;
|
|
24
33
|
} else {
|
|
@@ -26,6 +35,7 @@ public class DownloadBundleOptions {
|
|
|
26
35
|
}
|
|
27
36
|
this.bundleId = bundleId;
|
|
28
37
|
this.checksum = checksum;
|
|
38
|
+
this.signature = signature;
|
|
29
39
|
this.url = url;
|
|
30
40
|
}
|
|
31
41
|
|
|
@@ -44,6 +54,11 @@ public class DownloadBundleOptions {
|
|
|
44
54
|
return checksum;
|
|
45
55
|
}
|
|
46
56
|
|
|
57
|
+
@Nullable
|
|
58
|
+
public String getSignature() {
|
|
59
|
+
return signature;
|
|
60
|
+
}
|
|
61
|
+
|
|
47
62
|
@NonNull
|
|
48
63
|
public String getUrl() {
|
|
49
64
|
return url;
|
|
@@ -15,13 +15,27 @@ public class FetchLatestBundleResult implements Result {
|
|
|
15
15
|
@Nullable
|
|
16
16
|
private final String bundleId;
|
|
17
17
|
|
|
18
|
+
@Nullable
|
|
19
|
+
private final String checksum;
|
|
20
|
+
|
|
18
21
|
@Nullable
|
|
19
22
|
private final String downloadUrl;
|
|
20
23
|
|
|
21
|
-
|
|
24
|
+
@Nullable
|
|
25
|
+
private final String signature;
|
|
26
|
+
|
|
27
|
+
public FetchLatestBundleResult(
|
|
28
|
+
@Nullable ArtifactType artifactType,
|
|
29
|
+
@Nullable String bundleId,
|
|
30
|
+
@Nullable String checksum,
|
|
31
|
+
@Nullable String downloadUrl,
|
|
32
|
+
@Nullable String signature
|
|
33
|
+
) {
|
|
22
34
|
this.artifactType = artifactType;
|
|
23
35
|
this.bundleId = bundleId;
|
|
36
|
+
this.checksum = checksum;
|
|
24
37
|
this.downloadUrl = downloadUrl;
|
|
38
|
+
this.signature = signature;
|
|
25
39
|
}
|
|
26
40
|
|
|
27
41
|
@NonNull
|
|
@@ -33,9 +47,15 @@ public class FetchLatestBundleResult implements Result {
|
|
|
33
47
|
result.put("artifactType", "zip");
|
|
34
48
|
}
|
|
35
49
|
result.put("bundleId", bundleId == null ? JSONObject.NULL : bundleId);
|
|
50
|
+
if (checksum != null) {
|
|
51
|
+
result.put("checksum", checksum);
|
|
52
|
+
}
|
|
36
53
|
if (downloadUrl != null) {
|
|
37
54
|
result.put("downloadUrl", downloadUrl);
|
|
38
55
|
}
|
|
56
|
+
if (signature != null) {
|
|
57
|
+
result.put("signature", signature);
|
|
58
|
+
}
|
|
39
59
|
return result;
|
|
40
60
|
}
|
|
41
61
|
}
|
package/dist/docs.json
CHANGED
|
@@ -480,13 +480,21 @@
|
|
|
480
480
|
{
|
|
481
481
|
"text": "6.1.0",
|
|
482
482
|
"name": "since"
|
|
483
|
-
}
|
|
483
|
+
}
|
|
484
|
+
],
|
|
485
|
+
"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.",
|
|
486
|
+
"complexTypes": [],
|
|
487
|
+
"type": "string | undefined"
|
|
488
|
+
},
|
|
489
|
+
{
|
|
490
|
+
"name": "signature",
|
|
491
|
+
"tags": [
|
|
484
492
|
{
|
|
485
|
-
"text": "
|
|
486
|
-
"name": "
|
|
493
|
+
"text": "6.8.0",
|
|
494
|
+
"name": "since"
|
|
487
495
|
}
|
|
488
496
|
],
|
|
489
|
-
"docs": "The
|
|
497
|
+
"docs": "The signature of the self-hosted bundle as a signed SHA-256 hash\nin base64 format to verify the integrity of the bundle.\n\n**Attention**: Only supported for the `zip` artifact type.",
|
|
490
498
|
"complexTypes": [],
|
|
491
499
|
"type": "string | undefined"
|
|
492
500
|
},
|
|
@@ -544,6 +552,18 @@
|
|
|
544
552
|
"complexTypes": [],
|
|
545
553
|
"type": "string | null"
|
|
546
554
|
},
|
|
555
|
+
{
|
|
556
|
+
"name": "checksum",
|
|
557
|
+
"tags": [
|
|
558
|
+
{
|
|
559
|
+
"text": "6.8.0",
|
|
560
|
+
"name": "since"
|
|
561
|
+
}
|
|
562
|
+
],
|
|
563
|
+
"docs": "The checksum of the latest bundle if the bundle is self-hosted.\n\nIf the bundle is hosted on Capawesome Cloud, the checksum will be\nreturned as response header when downloading the bundle.",
|
|
564
|
+
"complexTypes": [],
|
|
565
|
+
"type": "string | undefined"
|
|
566
|
+
},
|
|
547
567
|
{
|
|
548
568
|
"name": "downloadUrl",
|
|
549
569
|
"tags": [
|
|
@@ -555,6 +575,18 @@
|
|
|
555
575
|
"docs": "The URL of the latest bundle to download.\nPass this URL to the `downloadBundle(...)` method to download the bundle.",
|
|
556
576
|
"complexTypes": [],
|
|
557
577
|
"type": "string | undefined"
|
|
578
|
+
},
|
|
579
|
+
{
|
|
580
|
+
"name": "signature",
|
|
581
|
+
"tags": [
|
|
582
|
+
{
|
|
583
|
+
"text": "6.8.0",
|
|
584
|
+
"name": "since"
|
|
585
|
+
}
|
|
586
|
+
],
|
|
587
|
+
"docs": "The signature of the latest bundle if the bundle is self-hosted.\n\nIf the bundle is hosted on Capawesome Cloud, the signature will be\nreturned as response header when downloading the bundle.",
|
|
588
|
+
"complexTypes": [],
|
|
589
|
+
"type": "string | undefined"
|
|
558
590
|
}
|
|
559
591
|
]
|
|
560
592
|
},
|
|
@@ -283,14 +283,23 @@ export interface DownloadBundleOptions {
|
|
|
283
283
|
*/
|
|
284
284
|
bundleId: string;
|
|
285
285
|
/**
|
|
286
|
-
* The checksum of the bundle
|
|
286
|
+
* The checksum of the self-hosted bundle as a SHA-256 hash
|
|
287
|
+
* in base64 format to verify the integrity of the bundle.
|
|
287
288
|
*
|
|
288
|
-
*
|
|
289
|
+
* **Attention**: Only supported for the `zip` artifact type.
|
|
289
290
|
*
|
|
290
291
|
* @since 6.1.0
|
|
291
|
-
* @deprecated The server should return a `X-Checksum` header instead.
|
|
292
292
|
*/
|
|
293
293
|
checksum?: string;
|
|
294
|
+
/**
|
|
295
|
+
* The signature of the self-hosted bundle as a signed SHA-256 hash
|
|
296
|
+
* in base64 format to verify the integrity of the bundle.
|
|
297
|
+
*
|
|
298
|
+
* **Attention**: Only supported for the `zip` artifact type.
|
|
299
|
+
*
|
|
300
|
+
* @since 6.8.0
|
|
301
|
+
*/
|
|
302
|
+
signature?: string;
|
|
294
303
|
/**
|
|
295
304
|
* The URL of the bundle to download.
|
|
296
305
|
*
|
|
@@ -340,6 +349,15 @@ export interface FetchLatestBundleResult {
|
|
|
340
349
|
* @since 6.6.0
|
|
341
350
|
*/
|
|
342
351
|
bundleId: string | null;
|
|
352
|
+
/**
|
|
353
|
+
* The checksum of the latest bundle if the bundle is self-hosted.
|
|
354
|
+
*
|
|
355
|
+
* If the bundle is hosted on Capawesome Cloud, the checksum will be
|
|
356
|
+
* returned as response header when downloading the bundle.
|
|
357
|
+
*
|
|
358
|
+
* @since 6.8.0
|
|
359
|
+
*/
|
|
360
|
+
checksum?: string;
|
|
343
361
|
/**
|
|
344
362
|
* The URL of the latest bundle to download.
|
|
345
363
|
* Pass this URL to the `downloadBundle(...)` method to download the bundle.
|
|
@@ -347,6 +365,15 @@ export interface FetchLatestBundleResult {
|
|
|
347
365
|
* @since 6.7.0
|
|
348
366
|
*/
|
|
349
367
|
downloadUrl?: string;
|
|
368
|
+
/**
|
|
369
|
+
* The signature of the latest bundle if the bundle is self-hosted.
|
|
370
|
+
*
|
|
371
|
+
* If the bundle is hosted on Capawesome Cloud, the signature will be
|
|
372
|
+
* returned as response header when downloading the bundle.
|
|
373
|
+
*
|
|
374
|
+
* @since 6.8.0
|
|
375
|
+
*/
|
|
376
|
+
signature?: string;
|
|
350
377
|
}
|
|
351
378
|
/**
|
|
352
379
|
* @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\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 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 default channel of the app.\n *\n * @since 6.3.0\n * @example 'production'\n */\n defaultChannel?: string;\n /**\n * Whether or not the plugin is enabled.\n *\n * @since 5.0.0\n * @default true\n */\n enabled?: boolean;\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 location of the server to use when using [Capawesome Cloud](https://capawesome.io/cloud).\n *\n * @since 6.2.0\n * @default 'us'\n * @example 'eu'\n * @deprecated This option will be removed in the future.\n */\n location?: 'us' | 'eu';\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 before resetting to the default bundle.\n *\n * @since 5.0.0\n * @default 10000\n */\n readyTimeout?: number;\n /**\n * Whether or not the app should be reset to the default bundle during an update.\n *\n * @since 5.0.0\n * @default true\n */\n resetOnUpdate?: boolean;\n };\n }\n}\n\nexport interface LiveUpdatePlugin {\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(options?: FetchLatestBundleOptions): Promise<FetchLatestBundleResult>;\n /**\n * Get the active bundle identifier.\n *\n * Only available on Android and iOS.\n *\n * @since 5.0.0\n * @deprecated Use `getCurrentBundle()` instead.\n */\n getBundle(): Promise<GetBundleResult>;\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 */\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 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 * 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 * 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 * 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<void>;\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 * 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 5.0.0\n * @deprecated Use `setNextBundle()` instead.\n */\n setBundle(options: SetBundleOptions): 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 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\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 * @since 5.0.0\n * @example '1.0.0'\n */\n bundleId: string;\n /**\n * The checksum of the bundle to verify the integrity of the ZIP file.\n *\n * Must be a SHA-256 hash in base64 format.\n *\n * @since 6.1.0\n * @deprecated The server should return a `X-Checksum` header instead.\n */\n checksum?: 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 must 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 must 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 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\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 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 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 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 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 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 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"]}
|
|
1
|
+
{"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"AAAA,wCAAwC","sourcesContent":["/// <reference types=\"@capacitor/cli\" />\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 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 default channel of the app.\n *\n * @since 6.3.0\n * @example 'production'\n */\n defaultChannel?: string;\n /**\n * Whether or not the plugin is enabled.\n *\n * @since 5.0.0\n * @default true\n */\n enabled?: boolean;\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 location of the server to use when using [Capawesome Cloud](https://capawesome.io/cloud).\n *\n * @since 6.2.0\n * @default 'us'\n * @example 'eu'\n * @deprecated This option will be removed in the future.\n */\n location?: 'us' | 'eu';\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 before resetting to the default bundle.\n *\n * @since 5.0.0\n * @default 10000\n */\n readyTimeout?: number;\n /**\n * Whether or not the app should be reset to the default bundle during an update.\n *\n * @since 5.0.0\n * @default true\n */\n resetOnUpdate?: boolean;\n };\n }\n}\n\nexport interface LiveUpdatePlugin {\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(options?: FetchLatestBundleOptions): Promise<FetchLatestBundleResult>;\n /**\n * Get the active bundle identifier.\n *\n * Only available on Android and iOS.\n *\n * @since 5.0.0\n * @deprecated Use `getCurrentBundle()` instead.\n */\n getBundle(): Promise<GetBundleResult>;\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 */\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 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 * 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 * 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 * 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<void>;\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 * 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 5.0.0\n * @deprecated Use `setNextBundle()` instead.\n */\n setBundle(options: SetBundleOptions): 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 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\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 * @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 6.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 6.8.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 must 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 must 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 6.8.0\n */\n checksum?: 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 6.8.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 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 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 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 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 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 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"]}
|
|
@@ -5,9 +5,10 @@ import Capacitor
|
|
|
5
5
|
private var artifactType: ArtifactType
|
|
6
6
|
private var bundleId: String
|
|
7
7
|
private var checksum: String?
|
|
8
|
+
private var signature: String?
|
|
8
9
|
private var url: String
|
|
9
10
|
|
|
10
|
-
init(artifactType: String, bundleId: String, checksum: String?, url: String) {
|
|
11
|
+
init(artifactType: String, bundleId: String, checksum: String?, signature: String?, url: String) {
|
|
11
12
|
if artifactType == "manifest" {
|
|
12
13
|
self.artifactType = .manifest
|
|
13
14
|
} else {
|
|
@@ -15,6 +16,7 @@ import Capacitor
|
|
|
15
16
|
}
|
|
16
17
|
self.bundleId = bundleId
|
|
17
18
|
self.checksum = checksum
|
|
19
|
+
self.signature = signature
|
|
18
20
|
self.url = url
|
|
19
21
|
}
|
|
20
22
|
|
|
@@ -30,6 +32,10 @@ import Capacitor
|
|
|
30
32
|
return checksum
|
|
31
33
|
}
|
|
32
34
|
|
|
35
|
+
func getSignature() -> String? {
|
|
36
|
+
return signature
|
|
37
|
+
}
|
|
38
|
+
|
|
33
39
|
func getUrl() -> String {
|
|
34
40
|
return url
|
|
35
41
|
}
|
|
@@ -4,12 +4,16 @@ import Capacitor
|
|
|
4
4
|
@objc public class FetchLatestBundleResult: NSObject, Result {
|
|
5
5
|
private let artifactType: ArtifactType?
|
|
6
6
|
private let bundleId: String?
|
|
7
|
+
private let checksum: String?
|
|
7
8
|
private let downloadUrl: String?
|
|
9
|
+
private let signature: String?
|
|
8
10
|
|
|
9
|
-
init(artifactType: ArtifactType?, bundleId: String?, downloadUrl: String?) {
|
|
11
|
+
init(artifactType: ArtifactType?, bundleId: String?, checksum: String?, downloadUrl: String?, signature: String?) {
|
|
10
12
|
self.artifactType = artifactType
|
|
11
13
|
self.bundleId = bundleId
|
|
14
|
+
self.checksum = checksum
|
|
12
15
|
self.downloadUrl = downloadUrl
|
|
16
|
+
self.signature = signature
|
|
13
17
|
}
|
|
14
18
|
|
|
15
19
|
public func toJSObject() -> AnyObject {
|
|
@@ -20,9 +24,15 @@ import Capacitor
|
|
|
20
24
|
result["artifactType"] = "zip"
|
|
21
25
|
}
|
|
22
26
|
result["bundleId"] = bundleId == nil ? NSNull() : bundleId
|
|
27
|
+
if let checksum = checksum {
|
|
28
|
+
result["checksum"] = checksum
|
|
29
|
+
}
|
|
23
30
|
if let downloadUrl = downloadUrl {
|
|
24
31
|
result["downloadUrl"] = downloadUrl
|
|
25
32
|
}
|
|
33
|
+
if let signature = signature {
|
|
34
|
+
result["signature"] = signature
|
|
35
|
+
}
|
|
26
36
|
return result as AnyObject
|
|
27
37
|
}
|
|
28
38
|
}
|
|
@@ -35,11 +35,12 @@ import CommonCrypto
|
|
|
35
35
|
|
|
36
36
|
if config.enabled {
|
|
37
37
|
if wasUpdated() && config.resetOnUpdate {
|
|
38
|
+
CAPLog.print("[", LiveUpdatePlugin.tag, "] ", "App was updated. Resetting to default bundle.")
|
|
38
39
|
reset()
|
|
39
40
|
} else {
|
|
40
41
|
startRollbackTimer()
|
|
41
42
|
}
|
|
42
|
-
|
|
43
|
+
saveCurrentBundleShortVersionStringAndBundleVersion()
|
|
43
44
|
}
|
|
44
45
|
}
|
|
45
46
|
|
|
@@ -64,6 +65,7 @@ import CommonCrypto
|
|
|
64
65
|
let artifactType = options.getArtifactType()
|
|
65
66
|
let bundleId = options.getBundleId()
|
|
66
67
|
let checksum = options.getChecksum()
|
|
68
|
+
let signature = options.getSignature()
|
|
67
69
|
let url = options.getUrl()
|
|
68
70
|
|
|
69
71
|
// Check if the bundle already exists
|
|
@@ -75,13 +77,13 @@ import CommonCrypto
|
|
|
75
77
|
if artifactType == .manifest {
|
|
76
78
|
try await downloadBundleOfTypeManifest(bundleId: bundleId, url: url)
|
|
77
79
|
} else {
|
|
78
|
-
try await downloadBundleOfTypeZip(bundleId: bundleId, url: url, checksum: checksum)
|
|
80
|
+
try await downloadBundleOfTypeZip(bundleId: bundleId, url: url, checksum: checksum, signature: signature)
|
|
79
81
|
}
|
|
80
82
|
}
|
|
81
83
|
|
|
82
84
|
@objc public func fetchLatestBundle(_ options: FetchLatestBundleOptions) async throws -> FetchLatestBundleResult {
|
|
83
85
|
let response: GetLatestBundleResponse? = try await self.fetchLatestBundle(options)
|
|
84
|
-
return FetchLatestBundleResult(artifactType: response?.artifactType, bundleId: response?.bundleId, downloadUrl: response?.url)
|
|
86
|
+
return FetchLatestBundleResult(artifactType: response?.artifactType, bundleId: response?.bundleId, checksum: response?.checksum, downloadUrl: response?.url, signature: response?.signature)
|
|
85
87
|
}
|
|
86
88
|
|
|
87
89
|
@objc public func getBundle(completion: @escaping (Result?, Error?) -> Void) {
|
|
@@ -222,6 +224,8 @@ import CommonCrypto
|
|
|
222
224
|
}
|
|
223
225
|
let artifactType = response.artifactType
|
|
224
226
|
let latestBundleId = response.bundleId
|
|
227
|
+
let checksum = response.checksum
|
|
228
|
+
let signature = response.signature
|
|
225
229
|
let downloadUrl = response.url
|
|
226
230
|
// Check if bundle already exists
|
|
227
231
|
if hasBundle(bundleId: latestBundleId) {
|
|
@@ -238,7 +242,7 @@ import CommonCrypto
|
|
|
238
242
|
if artifactType == .manifest {
|
|
239
243
|
try await downloadBundleOfTypeManifest(bundleId: latestBundleId, url: downloadUrl)
|
|
240
244
|
} else {
|
|
241
|
-
try await downloadBundleOfTypeZip(bundleId: latestBundleId, url: downloadUrl, checksum:
|
|
245
|
+
try await downloadBundleOfTypeZip(bundleId: latestBundleId, url: downloadUrl, checksum: checksum, signature: signature)
|
|
242
246
|
}
|
|
243
247
|
// Set the next bundle
|
|
244
248
|
setNextBundle(bundleId: latestBundleId)
|
|
@@ -362,7 +366,7 @@ import CommonCrypto
|
|
|
362
366
|
}
|
|
363
367
|
}
|
|
364
368
|
|
|
365
|
-
private func downloadAndVerifyFile(url: String, file: URL, checksum: String?) async throws {
|
|
369
|
+
private func downloadAndVerifyFile(url: String, file: URL, checksum: String?, signature: String?) async throws {
|
|
366
370
|
let destination: DownloadRequest.Destination = { _, _ in
|
|
367
371
|
return (file, [.createIntermediateDirectories])
|
|
368
372
|
}
|
|
@@ -380,8 +384,8 @@ import CommonCrypto
|
|
|
380
384
|
guard let response = result.response else {
|
|
381
385
|
throw CustomError.unknown
|
|
382
386
|
}
|
|
383
|
-
let checksum = checksum
|
|
384
|
-
let signature = LiveUpdateHttpClient.getSignatureFromResponse(response: response)
|
|
387
|
+
let checksum = checksum ?? LiveUpdateHttpClient.getChecksumFromResponse(response: response)
|
|
388
|
+
let signature = signature ?? LiveUpdateHttpClient.getSignatureFromResponse(response: response)
|
|
385
389
|
try verifyFile(url: file, checksum: checksum, signature: signature)
|
|
386
390
|
}
|
|
387
391
|
|
|
@@ -392,7 +396,7 @@ import CommonCrypto
|
|
|
392
396
|
var urlComponents = URLComponents(string: baseUrl)!
|
|
393
397
|
urlComponents.queryItems = parameters.map { URLQueryItem(name: $0.key, value: $0.value) }
|
|
394
398
|
let url = urlComponents.string!
|
|
395
|
-
try await self.downloadAndVerifyFile(url: url, file: fileURL, checksum: nil)
|
|
399
|
+
try await self.downloadAndVerifyFile(url: url, file: fileURL, checksum: nil, signature: nil)
|
|
396
400
|
return fileURL
|
|
397
401
|
}
|
|
398
402
|
|
|
@@ -433,11 +437,11 @@ import CommonCrypto
|
|
|
433
437
|
try await addBundleOfTypeManifest(bundleId: bundleId, directory: temporaryDirectory)
|
|
434
438
|
}
|
|
435
439
|
|
|
436
|
-
private func downloadBundleOfTypeZip(bundleId: String, url: String, checksum: String?) async throws {
|
|
440
|
+
private func downloadBundleOfTypeZip(bundleId: String, url: String, checksum: String?, signature: String?) async throws {
|
|
437
441
|
let timestamp = String(Int(Date().timeIntervalSince1970))
|
|
438
442
|
let temporaryZipFileUrl = self.cachesDirectoryUrl.appendingPathComponent(timestamp + ".zip")
|
|
439
443
|
// Download the bundle
|
|
440
|
-
try await downloadAndVerifyFile(url: url, file: temporaryZipFileUrl, checksum: checksum)
|
|
444
|
+
try await downloadAndVerifyFile(url: url, file: temporaryZipFileUrl, checksum: checksum, signature: signature)
|
|
441
445
|
// Add the bundle
|
|
442
446
|
try await addBundleOfTypeZip(bundleId: bundleId, zipFile: temporaryZipFileUrl)
|
|
443
447
|
}
|
|
@@ -611,10 +615,10 @@ import CommonCrypto
|
|
|
611
615
|
setCurrentCapacitorServerPathToDefaultWebAssetDir()
|
|
612
616
|
}
|
|
613
617
|
|
|
614
|
-
private func
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
+
private func saveCurrentBundleShortVersionStringAndBundleVersion() {
|
|
619
|
+
let currentBundleShortVersionString = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String
|
|
620
|
+
preferences.setLastBundleShortVersionString(currentBundleShortVersionString)
|
|
621
|
+
let currentBundleVersion = Bundle.main.infoDictionary?["CFBundleVersion"] as? String
|
|
618
622
|
preferences.setLastBundleVersion(currentBundleVersion)
|
|
619
623
|
}
|
|
620
624
|
|
|
@@ -786,19 +790,24 @@ import CommonCrypto
|
|
|
786
790
|
}
|
|
787
791
|
|
|
788
792
|
private func wasUpdated() -> Bool {
|
|
793
|
+
guard let lastBundleShortVersionString = preferences.getLastBundleShortVersionString() else {
|
|
794
|
+
// If the last bundle short version is not set, the app may have been updated
|
|
795
|
+
return true
|
|
796
|
+
}
|
|
789
797
|
guard let lastBundleVersionString = preferences.getLastBundleVersion() else {
|
|
790
|
-
|
|
798
|
+
// If the last bundle version is not set, the app may have been updated
|
|
799
|
+
return true
|
|
791
800
|
}
|
|
792
|
-
guard let
|
|
793
|
-
return
|
|
801
|
+
guard let currentBundleShortVersionString = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String else {
|
|
802
|
+
// If the current bundle short version is not set, return true for safety reasons
|
|
803
|
+
return true
|
|
794
804
|
}
|
|
795
805
|
guard let currentBundleVersionString = Bundle.main.infoDictionary?["CFBundleVersion"] as? String else {
|
|
796
|
-
return
|
|
797
|
-
|
|
798
|
-
guard let currentBundleVersion = Int(currentBundleVersionString) else {
|
|
799
|
-
return false
|
|
806
|
+
// If the current bundle version is not set, return true for safety reasons
|
|
807
|
+
return true
|
|
800
808
|
}
|
|
801
|
-
|
|
809
|
+
// `CFBundleVersion` is not unique across different versions of the app
|
|
810
|
+
return lastBundleShortVersionString + "_" + lastBundleVersionString != currentBundleShortVersionString + "_" + currentBundleVersionString
|
|
802
811
|
}
|
|
803
812
|
}
|
|
804
813
|
|
|
@@ -8,7 +8,7 @@ import Capacitor
|
|
|
8
8
|
@objc(LiveUpdatePlugin)
|
|
9
9
|
public class LiveUpdatePlugin: CAPPlugin {
|
|
10
10
|
public static let tag = "LiveUpdate"
|
|
11
|
-
public static let version = "6.
|
|
11
|
+
public static let version = "6.8.0"
|
|
12
12
|
public static let userDefaultsPrefix = "CapawesomeLiveUpdate" // DO NOT CHANGE
|
|
13
13
|
|
|
14
14
|
private var config: LiveUpdateConfig?
|
|
@@ -46,12 +46,13 @@ public class LiveUpdatePlugin: CAPPlugin {
|
|
|
46
46
|
return
|
|
47
47
|
}
|
|
48
48
|
let checksum = call.getString("checksum")
|
|
49
|
+
let signature = call.getString("signature")
|
|
49
50
|
guard let url = call.getString("url") else {
|
|
50
51
|
call.reject(CustomError.urlMissing.localizedDescription)
|
|
51
52
|
return
|
|
52
53
|
}
|
|
53
54
|
|
|
54
|
-
let options = DownloadBundleOptions(artifactType: artifactType, bundleId: bundleId, checksum: checksum, url: url)
|
|
55
|
+
let options = DownloadBundleOptions(artifactType: artifactType, bundleId: bundleId, checksum: checksum, signature: signature, url: url)
|
|
55
56
|
|
|
56
57
|
try await implementation?.downloadBundle(options)
|
|
57
58
|
self.resolveCall(call)
|
|
@@ -3,6 +3,7 @@ import Foundation
|
|
|
3
3
|
public class LiveUpdatePreferences: NSObject {
|
|
4
4
|
private let channelKey = "channel" // DO NOT CHANGE
|
|
5
5
|
private let customIdKey = "customId" // DO NOT CHANGE
|
|
6
|
+
private let lastBundleShortVersionStringKey = "lastBundleShortVersionString" // DO NOT CHANGE
|
|
6
7
|
private let lastBundleVersionKey = "lastBundleVersion" // DO NOT CHANGE
|
|
7
8
|
|
|
8
9
|
public func getChannel() -> String? {
|
|
@@ -13,6 +14,10 @@ public class LiveUpdatePreferences: NSObject {
|
|
|
13
14
|
return UserDefaults.standard.string(forKey: applyPrefix(to: customIdKey))
|
|
14
15
|
}
|
|
15
16
|
|
|
17
|
+
public func getLastBundleShortVersionString() -> String? {
|
|
18
|
+
return UserDefaults.standard.string(forKey: applyPrefix(to: lastBundleShortVersionStringKey))
|
|
19
|
+
}
|
|
20
|
+
|
|
16
21
|
public func getLastBundleVersion() -> String? {
|
|
17
22
|
return UserDefaults.standard.string(forKey: applyPrefix(to: lastBundleVersionKey))
|
|
18
23
|
}
|
|
@@ -31,8 +36,21 @@ public class LiveUpdatePreferences: NSObject {
|
|
|
31
36
|
UserDefaults.standard.synchronize()
|
|
32
37
|
}
|
|
33
38
|
|
|
34
|
-
public func
|
|
35
|
-
|
|
39
|
+
public func setLastBundleShortVersionString(_ value: String?) {
|
|
40
|
+
if let value = value {
|
|
41
|
+
UserDefaults.standard.set(value, forKey: applyPrefix(to: lastBundleShortVersionStringKey))
|
|
42
|
+
} else {
|
|
43
|
+
UserDefaults.standard.removeObject(forKey: applyPrefix(to: lastBundleShortVersionStringKey))
|
|
44
|
+
}
|
|
45
|
+
UserDefaults.standard.synchronize()
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
public func setLastBundleVersion(_ value: String?) {
|
|
49
|
+
if let value = value {
|
|
50
|
+
UserDefaults.standard.set(value, forKey: applyPrefix(to: lastBundleVersionKey))
|
|
51
|
+
} else {
|
|
52
|
+
UserDefaults.standard.removeObject(forKey: applyPrefix(to: lastBundleVersionKey))
|
|
53
|
+
}
|
|
36
54
|
UserDefaults.standard.synchronize()
|
|
37
55
|
}
|
|
38
56
|
|