@capawesome/capacitor-live-update 6.9.0 → 6.9.2
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/android/src/main/java/io/capawesome/capacitorjs/plugins/liveupdate/LiveUpdate.java +84 -57
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/liveupdate/LiveUpdatePlugin.java +2 -1
- package/ios/Plugin/LiveUpdate.swift +39 -12
- package/ios/Plugin/LiveUpdateHttpClient.swift +6 -1
- package/ios/Plugin/LiveUpdatePlugin.swift +1 -1
- package/package.json +1 -1
|
@@ -7,9 +7,11 @@ import android.content.pm.PackageManager;
|
|
|
7
7
|
import android.content.res.AssetManager;
|
|
8
8
|
import android.os.Build;
|
|
9
9
|
import android.os.Handler;
|
|
10
|
+
import android.os.Looper;
|
|
10
11
|
import android.util.Base64;
|
|
11
12
|
import androidx.annotation.NonNull;
|
|
12
13
|
import androidx.annotation.Nullable;
|
|
14
|
+
import androidx.core.content.pm.PackageInfoCompat;
|
|
13
15
|
import com.getcapacitor.Bridge;
|
|
14
16
|
import com.getcapacitor.Logger;
|
|
15
17
|
import com.getcapacitor.plugin.WebView;
|
|
@@ -103,7 +105,8 @@ public class LiveUpdate {
|
|
|
103
105
|
private final SharedPreferences.Editor webViewSettingsEditor;
|
|
104
106
|
|
|
105
107
|
private final String bundlesDirectory = "_capacitor_live_update_bundles"; // DO NOT CHANGE!
|
|
106
|
-
private final
|
|
108
|
+
private final String downloadsDirectory = "capawesome_capacitor_live_update_downloads";
|
|
109
|
+
private final Handler rollbackHandler = new Handler(Looper.getMainLooper());
|
|
107
110
|
private final String manifestFileName = "capawesome-live-update-manifest.json"; // DO NOT CHANGE!
|
|
108
111
|
|
|
109
112
|
private boolean initialPageLoaded = false;
|
|
@@ -121,6 +124,9 @@ public class LiveUpdate {
|
|
|
121
124
|
// Set the device ID on the HTTP client
|
|
122
125
|
this.httpClient.setDeviceId(getDeviceId());
|
|
123
126
|
|
|
127
|
+
// Delete the leftovers of downloads that were interrupted by a process kill
|
|
128
|
+
tryDeleteDownloadsDirectory();
|
|
129
|
+
|
|
124
130
|
if (config.getEnabled()) {
|
|
125
131
|
boolean wasUpdated = wasUpdated();
|
|
126
132
|
if (wasUpdated) {
|
|
@@ -560,7 +566,10 @@ public class LiveUpdate {
|
|
|
560
566
|
|
|
561
567
|
// Move the bundle directory to the bundles directory
|
|
562
568
|
File bundleDirectory = buildBundleDirectoryFor(bundleId);
|
|
563
|
-
indexHtmlFile.getParentFile().renameTo(bundleDirectory);
|
|
569
|
+
boolean moved = indexHtmlFile.getParentFile().renameTo(bundleDirectory);
|
|
570
|
+
if (!moved) {
|
|
571
|
+
throw new Exception(LiveUpdatePlugin.ERROR_BUNDLE_MOVE_FAILED);
|
|
572
|
+
}
|
|
564
573
|
}
|
|
565
574
|
|
|
566
575
|
private void addBundleOfTypeManifest(@NonNull String bundleId, @NonNull File directory) throws Exception {
|
|
@@ -569,7 +578,7 @@ public class LiveUpdate {
|
|
|
569
578
|
|
|
570
579
|
private void addBundleOfTypeZip(@NonNull String bundleId, @NonNull File zipFile) throws Exception {
|
|
571
580
|
// Unzip the file to the bundle directory
|
|
572
|
-
File unzippedDirectory =
|
|
581
|
+
File unzippedDirectory = unzipDownloadedBundle(zipFile);
|
|
573
582
|
// Add the bundle
|
|
574
583
|
addBundle(bundleId, unzippedDirectory);
|
|
575
584
|
}
|
|
@@ -582,14 +591,8 @@ public class LiveUpdate {
|
|
|
582
591
|
return new File(plugin.getContext().getFilesDir(), bundlesDirectory + "/" + bundleId);
|
|
583
592
|
}
|
|
584
593
|
|
|
585
|
-
private File
|
|
586
|
-
|
|
587
|
-
return new File(plugin.getContext().getCacheDir(), fileName);
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
private File buildTemporaryZipFile() {
|
|
591
|
-
String fileName = UUID.randomUUID().toString() + ".zip";
|
|
592
|
-
return new File(plugin.getContext().getCacheDir(), fileName);
|
|
594
|
+
private File buildDownloadsDirectory() {
|
|
595
|
+
return new File(plugin.getContext().getCacheDir(), downloadsDirectory);
|
|
593
596
|
}
|
|
594
597
|
|
|
595
598
|
private void copyCurrentBundleFile(@NonNull ManifestItem fileToCopy, @NonNull File destinationDirectory) throws IOException {
|
|
@@ -676,10 +679,10 @@ public class LiveUpdate {
|
|
|
676
679
|
}
|
|
677
680
|
}
|
|
678
681
|
|
|
679
|
-
private File
|
|
680
|
-
File
|
|
681
|
-
|
|
682
|
-
return
|
|
682
|
+
private File createTemporaryDownloadDirectory() {
|
|
683
|
+
File temporaryDirectory = new File(buildDownloadsDirectory(), UUID.randomUUID().toString());
|
|
684
|
+
temporaryDirectory.mkdirs();
|
|
685
|
+
return temporaryDirectory;
|
|
683
686
|
}
|
|
684
687
|
|
|
685
688
|
private void deleteBundleById(@NonNull String bundleId) {
|
|
@@ -705,6 +708,23 @@ public class LiveUpdate {
|
|
|
705
708
|
file.delete();
|
|
706
709
|
}
|
|
707
710
|
|
|
711
|
+
@NonNull
|
|
712
|
+
private EmptyCallback deleteTemporaryDirectoryOnCompletion(@NonNull File temporaryDirectory, @NonNull EmptyCallback callback) {
|
|
713
|
+
return new EmptyCallback() {
|
|
714
|
+
@Override
|
|
715
|
+
public void success() {
|
|
716
|
+
deleteFileRecursively(temporaryDirectory);
|
|
717
|
+
callback.success();
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
@Override
|
|
721
|
+
public void error(@NonNull Exception exception) {
|
|
722
|
+
deleteFileRecursively(temporaryDirectory);
|
|
723
|
+
callback.error(exception);
|
|
724
|
+
}
|
|
725
|
+
};
|
|
726
|
+
}
|
|
727
|
+
|
|
708
728
|
private void deleteUnusedBundles() {
|
|
709
729
|
String[] bundleIds = getDownloadedBundleIds();
|
|
710
730
|
for (String bundleId : bundleIds) {
|
|
@@ -875,10 +895,10 @@ public class LiveUpdate {
|
|
|
875
895
|
@NonNull String downloadUrl,
|
|
876
896
|
@NonNull EmptyCallback completionCallback
|
|
877
897
|
) {
|
|
898
|
+
// Create a temporary directory that is deleted once the download completed or failed
|
|
899
|
+
File temporaryDirectory = createTemporaryDownloadDirectory();
|
|
900
|
+
EmptyCallback callback = deleteTemporaryDirectoryOnCompletion(temporaryDirectory, completionCallback);
|
|
878
901
|
try {
|
|
879
|
-
// Create a temporary directory
|
|
880
|
-
File temporaryDirectory = createTemporaryDirectory();
|
|
881
|
-
|
|
882
902
|
// Download the latest manifest
|
|
883
903
|
downloadBundleFile(
|
|
884
904
|
downloadUrl,
|
|
@@ -928,31 +948,31 @@ public class LiveUpdate {
|
|
|
928
948
|
try {
|
|
929
949
|
// Add the bundle
|
|
930
950
|
addBundleOfTypeManifest(bundleId, temporaryDirectory);
|
|
931
|
-
|
|
951
|
+
callback.success();
|
|
932
952
|
} catch (Exception e) {
|
|
933
|
-
|
|
953
|
+
callback.error(e);
|
|
934
954
|
}
|
|
935
955
|
}
|
|
936
956
|
|
|
937
957
|
@Override
|
|
938
958
|
public void error(@NonNull Exception exception) {
|
|
939
|
-
|
|
959
|
+
callback.error(exception);
|
|
940
960
|
}
|
|
941
961
|
}
|
|
942
962
|
);
|
|
943
963
|
} catch (Exception e) {
|
|
944
|
-
|
|
964
|
+
callback.error(e);
|
|
945
965
|
}
|
|
946
966
|
}
|
|
947
967
|
|
|
948
968
|
@Override
|
|
949
969
|
public void error(@NonNull Exception exception) {
|
|
950
|
-
|
|
970
|
+
callback.error(exception);
|
|
951
971
|
}
|
|
952
972
|
}
|
|
953
973
|
);
|
|
954
974
|
} catch (Exception e) {
|
|
955
|
-
|
|
975
|
+
callback.error(e);
|
|
956
976
|
}
|
|
957
977
|
}
|
|
958
978
|
|
|
@@ -963,39 +983,42 @@ public class LiveUpdate {
|
|
|
963
983
|
@NonNull String downloadUrl,
|
|
964
984
|
@NonNull EmptyCallback completionCallback
|
|
965
985
|
) {
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
986
|
+
// Create a temporary directory that is deleted once the download completed or failed
|
|
987
|
+
File temporaryDirectory = createTemporaryDownloadDirectory();
|
|
988
|
+
EmptyCallback callback = deleteTemporaryDirectoryOnCompletion(temporaryDirectory, completionCallback);
|
|
989
|
+
File zipFile = new File(temporaryDirectory, "bundle.zip");
|
|
990
|
+
try {
|
|
991
|
+
// Download the bundle
|
|
992
|
+
downloadAndVerifyFile(
|
|
993
|
+
downloadUrl,
|
|
994
|
+
zipFile,
|
|
995
|
+
checksum,
|
|
996
|
+
signature,
|
|
997
|
+
(downloadedBytes, totalBytes) -> {
|
|
998
|
+
DownloadBundleProgressEvent event = new DownloadBundleProgressEvent(bundleId, downloadedBytes, totalBytes);
|
|
999
|
+
notifyDownloadBundleProgressListeners(event);
|
|
1000
|
+
},
|
|
1001
|
+
new EmptyCallback() {
|
|
1002
|
+
@Override
|
|
1003
|
+
public void success() {
|
|
1004
|
+
try {
|
|
1005
|
+
// Add the bundle
|
|
1006
|
+
addBundleOfTypeZip(bundleId, zipFile);
|
|
1007
|
+
callback.success();
|
|
1008
|
+
} catch (Exception e) {
|
|
1009
|
+
callback.error(e);
|
|
1010
|
+
}
|
|
988
1011
|
}
|
|
989
|
-
}
|
|
990
1012
|
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
completionCallback.error(exception);
|
|
1013
|
+
@Override
|
|
1014
|
+
public void error(@NonNull Exception exception) {
|
|
1015
|
+
callback.error(exception);
|
|
1016
|
+
}
|
|
996
1017
|
}
|
|
997
|
-
|
|
998
|
-
)
|
|
1018
|
+
);
|
|
1019
|
+
} catch (Exception e) {
|
|
1020
|
+
callback.error(e);
|
|
1021
|
+
}
|
|
999
1022
|
}
|
|
1000
1023
|
|
|
1001
1024
|
private void fetchLatestBundleInternal(
|
|
@@ -1199,7 +1222,7 @@ public class LiveUpdate {
|
|
|
1199
1222
|
}
|
|
1200
1223
|
|
|
1201
1224
|
private int getVersionCodeAsInt() throws PackageManager.NameNotFoundException {
|
|
1202
|
-
return getPackageInfo()
|
|
1225
|
+
return (int) PackageInfoCompat.getLongVersionCode(getPackageInfo());
|
|
1203
1226
|
}
|
|
1204
1227
|
|
|
1205
1228
|
private String getVersionCodeAsString() throws PackageManager.NameNotFoundException {
|
|
@@ -1458,8 +1481,12 @@ public class LiveUpdate {
|
|
|
1458
1481
|
}
|
|
1459
1482
|
}
|
|
1460
1483
|
|
|
1461
|
-
private
|
|
1462
|
-
|
|
1484
|
+
private void tryDeleteDownloadsDirectory() {
|
|
1485
|
+
deleteFileRecursively(buildDownloadsDirectory());
|
|
1486
|
+
}
|
|
1487
|
+
|
|
1488
|
+
private File unzipDownloadedBundle(@NonNull File zipFile) throws IOException {
|
|
1489
|
+
File destination = new File(zipFile.getParentFile(), "bundle");
|
|
1463
1490
|
String destinationPath = destination.getPath();
|
|
1464
1491
|
ZipFile zip = new ZipFile(zipFile);
|
|
1465
1492
|
// 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
|
@@ -39,12 +39,13 @@ import io.capawesome.capacitorjs.plugins.liveupdate.interfaces.Result;
|
|
|
39
39
|
public class LiveUpdatePlugin extends Plugin {
|
|
40
40
|
|
|
41
41
|
public static final String TAG = "LiveUpdate";
|
|
42
|
-
public static final String VERSION = "6.9.
|
|
42
|
+
public static final String VERSION = "6.9.2";
|
|
43
43
|
public static final String SHARED_PREFERENCES_NAME = "CapawesomeLiveUpdate"; // DO NOT CHANGE
|
|
44
44
|
public static final String ERROR_APP_ID_MISSING = "appId must be configured.";
|
|
45
45
|
public static final String ERROR_BUNDLE_EXISTS = "bundle already exists.";
|
|
46
46
|
public static final String ERROR_BUNDLE_ID_MISSING = "bundleId must be provided.";
|
|
47
47
|
public static final String ERROR_BUNDLE_INDEX_HTML_MISSING = "The bundle does not contain an index.html file.";
|
|
48
|
+
public static final String ERROR_BUNDLE_MOVE_FAILED = "Bundle could not be moved.";
|
|
48
49
|
public static final String ERROR_BUNDLE_NOT_FOUND = "bundle not found.";
|
|
49
50
|
public static final String ERROR_CHECKSUM_CALCULATION_FAILED = "Failed to calculate checksum.";
|
|
50
51
|
public static final String ERROR_CHECKSUM_MISMATCH = "Checksum mismatch.";
|
|
@@ -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!
|
|
@@ -34,6 +35,9 @@ import CommonCrypto
|
|
|
34
35
|
// Set the device ID on the HTTP client
|
|
35
36
|
httpClient.setDeviceId(getDeviceId())
|
|
36
37
|
|
|
38
|
+
// Delete the leftovers of downloads that were interrupted by a process kill
|
|
39
|
+
tryDeleteDownloadsDirectory()
|
|
40
|
+
|
|
37
41
|
if config.enabled {
|
|
38
42
|
let wasUpdated = wasUpdated()
|
|
39
43
|
if wasUpdated {
|
|
@@ -381,7 +385,7 @@ import CommonCrypto
|
|
|
381
385
|
|
|
382
386
|
private func addBundleOfTypeZip(bundleId: String, zipFile: URL) async throws {
|
|
383
387
|
// Unzip the bundle
|
|
384
|
-
let unzippedDirectory = try self.
|
|
388
|
+
let unzippedDirectory = try self.unzipDownloadedBundle(zipFile: zipFile)
|
|
385
389
|
// Add the bundle
|
|
386
390
|
try self.addBundle(bundleId: bundleId, directory: unzippedDirectory)
|
|
387
391
|
}
|
|
@@ -405,6 +409,10 @@ import CommonCrypto
|
|
|
405
409
|
return url
|
|
406
410
|
}
|
|
407
411
|
|
|
412
|
+
private func buildDownloadsDirectoryUrl() -> URL {
|
|
413
|
+
return cachesDirectoryUrl.appendingPathComponent(downloadsDirectory)
|
|
414
|
+
}
|
|
415
|
+
|
|
408
416
|
private func copyCurrentBundleFile(fileToCopy: ManifestItem, toDirectory: URL) throws {
|
|
409
417
|
let currentBundleId = getCurrentBundleId()
|
|
410
418
|
let destination = toDirectory.appendingPathComponent(fileToCopy.href)
|
|
@@ -454,8 +462,8 @@ import CommonCrypto
|
|
|
454
462
|
}
|
|
455
463
|
}
|
|
456
464
|
|
|
457
|
-
private func
|
|
458
|
-
let temporaryDirectory =
|
|
465
|
+
private func createTemporaryDownloadDirectory() throws -> URL {
|
|
466
|
+
let temporaryDirectory = buildDownloadsDirectoryUrl().appendingPathComponent(UUID().uuidString)
|
|
459
467
|
try FileManager.default.createDirectory(at: temporaryDirectory, withIntermediateDirectories: true, attributes: nil)
|
|
460
468
|
return temporaryDirectory
|
|
461
469
|
}
|
|
@@ -489,7 +497,8 @@ import CommonCrypto
|
|
|
489
497
|
|
|
490
498
|
private func downloadAndVerifyFile(url: String, file: URL, checksum: String?, signature: String?, callback: ((Progress) -> Void)?) async throws {
|
|
491
499
|
let destination: DownloadRequest.Destination = { _, _ in
|
|
492
|
-
|
|
500
|
+
// `removePreviousFile` ensures that a leftover file from a failed attempt does not fail the download
|
|
501
|
+
return (file, [.createIntermediateDirectories, .removePreviousFile])
|
|
493
502
|
}
|
|
494
503
|
let urlComponents = URLComponents(string: url)!
|
|
495
504
|
let result = try await httpClient.download(url: urlComponents.asURL(), destination: destination, callback: callback)
|
|
@@ -562,8 +571,9 @@ import CommonCrypto
|
|
|
562
571
|
}
|
|
563
572
|
|
|
564
573
|
private func downloadBundleOfTypeManifest(bundleId: String, url: String) async throws {
|
|
565
|
-
// Create a temporary directory
|
|
566
|
-
let temporaryDirectory = try
|
|
574
|
+
// Create a temporary directory that is deleted once the download completed or failed
|
|
575
|
+
let temporaryDirectory = try createTemporaryDownloadDirectory()
|
|
576
|
+
defer { tryDeleteDirectory(temporaryDirectory) }
|
|
567
577
|
// Download the latest manifest
|
|
568
578
|
let latestManifestFile = try await downloadBundleFile(baseUrl: url, href: manifestFileName, directory: temporaryDirectory, callback: nil)
|
|
569
579
|
let latestManifest = try loadManifest(file: latestManifestFile)
|
|
@@ -594,15 +604,17 @@ import CommonCrypto
|
|
|
594
604
|
}
|
|
595
605
|
|
|
596
606
|
private func downloadBundleOfTypeZip(bundleId: String, checksum: String?, signature: String?, url: String) async throws {
|
|
597
|
-
|
|
598
|
-
let
|
|
607
|
+
// Create a temporary directory that is deleted once the download completed or failed
|
|
608
|
+
let temporaryDirectory = try createTemporaryDownloadDirectory()
|
|
609
|
+
defer { tryDeleteDirectory(temporaryDirectory) }
|
|
610
|
+
let zipFile = temporaryDirectory.appendingPathComponent("bundle.zip")
|
|
599
611
|
// Download the bundle
|
|
600
|
-
try await downloadAndVerifyFile(url: url, file:
|
|
612
|
+
try await downloadAndVerifyFile(url: url, file: zipFile, checksum: checksum, signature: signature, callback: { progress in
|
|
601
613
|
let event = DownloadBundleProgressEvent(bundleId: bundleId, downloadedBytes: progress.completedUnitCount, totalBytes: progress.totalUnitCount)
|
|
602
614
|
self.notifyDownloadBundleProgressListeners(event)
|
|
603
615
|
})
|
|
604
616
|
// Add the bundle
|
|
605
|
-
try await addBundleOfTypeZip(bundleId: bundleId, zipFile:
|
|
617
|
+
try await addBundleOfTypeZip(bundleId: bundleId, zipFile: zipFile)
|
|
606
618
|
}
|
|
607
619
|
|
|
608
620
|
private func fetchLatestBundle(_ options: FetchLatestBundleOptions) async throws -> GetLatestBundleResponse? {
|
|
@@ -984,8 +996,23 @@ import CommonCrypto
|
|
|
984
996
|
}
|
|
985
997
|
}
|
|
986
998
|
|
|
987
|
-
private func
|
|
988
|
-
|
|
999
|
+
private func tryDeleteDirectory(_ url: URL) {
|
|
1000
|
+
guard FileManager.default.fileExists(atPath: url.path) else {
|
|
1001
|
+
return
|
|
1002
|
+
}
|
|
1003
|
+
do {
|
|
1004
|
+
try FileManager.default.removeItem(at: url)
|
|
1005
|
+
} catch {
|
|
1006
|
+
CAPLog.print("[", LiveUpdatePlugin.tag, "] ", "Failed to delete directory: \(url.path)")
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
|
|
1010
|
+
private func tryDeleteDownloadsDirectory() {
|
|
1011
|
+
tryDeleteDirectory(buildDownloadsDirectoryUrl())
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
private func unzipDownloadedBundle(zipFile: URL) throws -> URL {
|
|
1015
|
+
let destinationDirectory = zipFile.deletingLastPathComponent().appendingPathComponent("bundle")
|
|
989
1016
|
try FileManager.default.createDirectory(at: destinationDirectory, withIntermediateDirectories: true, attributes: nil)
|
|
990
1017
|
try FileManager.default.unzipItem(at: zipFile, to: destinationDirectory)
|
|
991
1018
|
return destinationDirectory
|
|
@@ -27,13 +27,16 @@ public class LiveUpdateHttpClient: NSObject {
|
|
|
27
27
|
|
|
28
28
|
public func download(url: URL, destination: @escaping DownloadRequest.Destination, callback: ((Progress) -> Void)?) async throws -> AFDownloadResponse<Data> {
|
|
29
29
|
var request = URLRequest(url: url)
|
|
30
|
+
// Ignore the URL cache so that a cached response is never replayed for a deterministic request URL
|
|
31
|
+
request.cachePolicy = .reloadIgnoringLocalCacheData
|
|
30
32
|
request.httpMethod = HTTPMethod.get.rawValue
|
|
31
33
|
request.timeoutInterval = Double(config.httpTimeout) / 1000.0
|
|
32
34
|
if let deviceId = deviceId, !deviceId.isEmpty {
|
|
33
35
|
request.setValue(deviceId, forHTTPHeaderField: "X-Device-Id")
|
|
34
36
|
}
|
|
35
37
|
return try await withCheckedThrowingContinuation { continuation in
|
|
36
|
-
|
|
38
|
+
// `validate()` treats non-2xx responses as errors so that an error body is never saved as a bundle file
|
|
39
|
+
AF.download(request, to: destination).validate().downloadProgress { progress in
|
|
37
40
|
if let callback = callback {
|
|
38
41
|
callback(progress)
|
|
39
42
|
}
|
|
@@ -45,6 +48,8 @@ public class LiveUpdateHttpClient: NSObject {
|
|
|
45
48
|
|
|
46
49
|
public func request<T: Decodable>(url: URL, type: T.Type) async throws -> AFDataResponse<T> {
|
|
47
50
|
var request = URLRequest(url: url)
|
|
51
|
+
// Ignore the URL cache so that a cached response is never replayed for a deterministic request URL
|
|
52
|
+
request.cachePolicy = .reloadIgnoringLocalCacheData
|
|
48
53
|
request.httpMethod = HTTPMethod.get.rawValue
|
|
49
54
|
request.timeoutInterval = Double(config.httpTimeout) / 1000.0
|
|
50
55
|
if let deviceId = deviceId, !deviceId.isEmpty {
|
|
@@ -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 = "6.9.
|
|
11
|
+
public static let version = "6.9.2"
|
|
12
12
|
public static let userDefaultsPrefix = "CapawesomeLiveUpdate" // DO NOT CHANGE
|
|
13
13
|
|
|
14
14
|
public let identifier = "LiveUpdatePlugin"
|