@capgo/capacitor-updater 7.15.3 → 7.17.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/android/src/main/java/ee/forgr/capacitor_updater/CapacitorUpdaterPlugin.java +51 -13
- package/android/src/main/java/ee/forgr/capacitor_updater/CapgoUpdater.java +36 -0
- package/ios/Sources/CapacitorUpdaterPlugin/CapacitorUpdaterPlugin.swift +47 -10
- package/ios/Sources/CapacitorUpdaterPlugin/CapgoUpdater.swift +36 -0
- package/package.json +1 -1
|
@@ -33,9 +33,11 @@ import java.net.URL;
|
|
|
33
33
|
import java.util.ArrayList;
|
|
34
34
|
import java.util.Arrays;
|
|
35
35
|
import java.util.Date;
|
|
36
|
+
import java.util.HashSet;
|
|
36
37
|
import java.util.List;
|
|
37
38
|
import java.util.Map;
|
|
38
39
|
import java.util.Objects;
|
|
40
|
+
import java.util.Set;
|
|
39
41
|
import java.util.Timer;
|
|
40
42
|
import java.util.TimerTask;
|
|
41
43
|
import java.util.UUID;
|
|
@@ -58,7 +60,7 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
58
60
|
private static final String statsUrlDefault = "https://plugin.capgo.app/stats";
|
|
59
61
|
private static final String channelUrlDefault = "https://plugin.capgo.app/channel_self";
|
|
60
62
|
|
|
61
|
-
private final String PLUGIN_VERSION = "7.
|
|
63
|
+
private final String PLUGIN_VERSION = "7.17.0";
|
|
62
64
|
private static final String DELAY_CONDITION_PREFERENCES = "";
|
|
63
65
|
|
|
64
66
|
private SharedPreferences.Editor editor;
|
|
@@ -443,6 +445,14 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
443
445
|
logger.error("Failed to delete: " + bundle.getId() + " " + e.getMessage());
|
|
444
446
|
}
|
|
445
447
|
}
|
|
448
|
+
final List<BundleInfo> storedBundles = this.implementation.list(true);
|
|
449
|
+
final Set<String> allowedIds = new HashSet<>();
|
|
450
|
+
for (final BundleInfo info : storedBundles) {
|
|
451
|
+
if (info != null && info.getId() != null && !info.getId().isEmpty()) {
|
|
452
|
+
allowedIds.add(info.getId());
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
this.implementation.cleanupDownloadDirectories(allowedIds);
|
|
446
456
|
}
|
|
447
457
|
this.editor.putString("LatestNativeBuildVersion", this.currentBuildVersion);
|
|
448
458
|
this.editor.apply();
|
|
@@ -1188,7 +1198,7 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
1188
1198
|
}
|
|
1189
1199
|
|
|
1190
1200
|
private void endBackGroundTaskWithNotif(String msg, String latestVersionName, BundleInfo current, Boolean error) {
|
|
1191
|
-
endBackGroundTaskWithNotif(msg, latestVersionName, current, error, false);
|
|
1201
|
+
endBackGroundTaskWithNotif(msg, latestVersionName, current, error, false, "download_fail", "downloadFailed");
|
|
1192
1202
|
}
|
|
1193
1203
|
|
|
1194
1204
|
private void endBackGroundTaskWithNotif(
|
|
@@ -1197,6 +1207,18 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
1197
1207
|
BundleInfo current,
|
|
1198
1208
|
Boolean error,
|
|
1199
1209
|
Boolean isDirectUpdate
|
|
1210
|
+
) {
|
|
1211
|
+
endBackGroundTaskWithNotif(msg, latestVersionName, current, error, isDirectUpdate, "download_fail", "downloadFailed");
|
|
1212
|
+
}
|
|
1213
|
+
|
|
1214
|
+
private void endBackGroundTaskWithNotif(
|
|
1215
|
+
String msg,
|
|
1216
|
+
String latestVersionName,
|
|
1217
|
+
BundleInfo current,
|
|
1218
|
+
Boolean error,
|
|
1219
|
+
Boolean isDirectUpdate,
|
|
1220
|
+
String failureAction,
|
|
1221
|
+
String failureEvent
|
|
1200
1222
|
) {
|
|
1201
1223
|
if (error) {
|
|
1202
1224
|
logger.info(
|
|
@@ -1207,10 +1229,10 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
1207
1229
|
"latestVersionName: " +
|
|
1208
1230
|
latestVersionName
|
|
1209
1231
|
);
|
|
1210
|
-
this.implementation.sendStats(
|
|
1232
|
+
this.implementation.sendStats(failureAction, current.getVersionName());
|
|
1211
1233
|
final JSObject ret = new JSObject();
|
|
1212
1234
|
ret.put("version", latestVersionName);
|
|
1213
|
-
this.notifyListeners(
|
|
1235
|
+
this.notifyListeners(failureEvent, ret);
|
|
1214
1236
|
}
|
|
1215
1237
|
final JSObject ret = new JSObject();
|
|
1216
1238
|
ret.put("bundle", mapToJSObject(current.toJSONMap()));
|
|
@@ -1235,13 +1257,26 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
1235
1257
|
if (jsRes.has("error")) {
|
|
1236
1258
|
String error = jsRes.getString("error");
|
|
1237
1259
|
logger.error("getLatest failed with error: " + error);
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1260
|
+
String latestVersion = jsRes.has("version") ? jsRes.getString("version") : current.getVersionName();
|
|
1261
|
+
if ("response_error".equals(error)) {
|
|
1262
|
+
CapacitorUpdaterPlugin.this.endBackGroundTaskWithNotif(
|
|
1263
|
+
"Network error: " + error,
|
|
1264
|
+
latestVersion,
|
|
1265
|
+
current,
|
|
1266
|
+
true,
|
|
1267
|
+
shouldDirectUpdate
|
|
1268
|
+
);
|
|
1269
|
+
} else {
|
|
1270
|
+
CapacitorUpdaterPlugin.this.endBackGroundTaskWithNotif(
|
|
1271
|
+
error,
|
|
1272
|
+
latestVersion,
|
|
1273
|
+
current,
|
|
1274
|
+
true,
|
|
1275
|
+
shouldDirectUpdate,
|
|
1276
|
+
"backend_refusal",
|
|
1277
|
+
"backendRefused"
|
|
1278
|
+
);
|
|
1279
|
+
}
|
|
1245
1280
|
return;
|
|
1246
1281
|
}
|
|
1247
1282
|
|
|
@@ -1253,12 +1288,15 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
1253
1288
|
majorAvailable.put("version", jsRes.getString("version"));
|
|
1254
1289
|
CapacitorUpdaterPlugin.this.notifyListeners("majorAvailable", majorAvailable);
|
|
1255
1290
|
}
|
|
1291
|
+
String latestVersion = jsRes.has("version") ? jsRes.getString("version") : current.getVersionName();
|
|
1256
1292
|
CapacitorUpdaterPlugin.this.endBackGroundTaskWithNotif(
|
|
1257
1293
|
jsRes.getString("message"),
|
|
1258
|
-
|
|
1294
|
+
latestVersion,
|
|
1259
1295
|
current,
|
|
1260
1296
|
true,
|
|
1261
|
-
shouldDirectUpdate
|
|
1297
|
+
shouldDirectUpdate,
|
|
1298
|
+
"backend_refusal",
|
|
1299
|
+
"backendRefused"
|
|
1262
1300
|
);
|
|
1263
1301
|
return;
|
|
1264
1302
|
}
|
|
@@ -32,6 +32,7 @@ import java.util.Iterator;
|
|
|
32
32
|
import java.util.List;
|
|
33
33
|
import java.util.Map;
|
|
34
34
|
import java.util.Objects;
|
|
35
|
+
import java.util.Set;
|
|
35
36
|
import java.util.concurrent.CompletableFuture;
|
|
36
37
|
import java.util.concurrent.ConcurrentHashMap;
|
|
37
38
|
import java.util.concurrent.TimeUnit;
|
|
@@ -466,6 +467,41 @@ public class CapgoUpdater {
|
|
|
466
467
|
}
|
|
467
468
|
}
|
|
468
469
|
|
|
470
|
+
public void cleanupDownloadDirectories(final Set<String> allowedIds) {
|
|
471
|
+
if (this.documentsDir == null) {
|
|
472
|
+
logger.warn("Documents directory is null, skipping download cleanup");
|
|
473
|
+
return;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
final File bundleRoot = new File(this.documentsDir, bundleDirectory);
|
|
477
|
+
if (!bundleRoot.exists() || !bundleRoot.isDirectory()) {
|
|
478
|
+
return;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
final File[] entries = bundleRoot.listFiles();
|
|
482
|
+
if (entries != null) {
|
|
483
|
+
for (final File entry : entries) {
|
|
484
|
+
if (!entry.isDirectory()) {
|
|
485
|
+
continue;
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
final String id = entry.getName();
|
|
489
|
+
|
|
490
|
+
if (allowedIds != null && allowedIds.contains(id)) {
|
|
491
|
+
continue;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
try {
|
|
495
|
+
this.deleteDirectory(entry);
|
|
496
|
+
this.removeBundleInfo(id);
|
|
497
|
+
logger.info("Deleted orphan bundle directory: " + id);
|
|
498
|
+
} catch (IOException e) {
|
|
499
|
+
logger.error("Failed to delete orphan bundle directory: " + id + " " + e.getMessage());
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
|
|
469
505
|
private void safeDelete(final File target) {
|
|
470
506
|
if (target == null || !target.exists()) {
|
|
471
507
|
return;
|
|
@@ -50,7 +50,7 @@ public class CapacitorUpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
50
50
|
CAPPluginMethod(name: "isShakeMenuEnabled", returnType: CAPPluginReturnPromise)
|
|
51
51
|
]
|
|
52
52
|
public var implementation = CapgoUpdater()
|
|
53
|
-
private let PLUGIN_VERSION: String = "7.
|
|
53
|
+
private let PLUGIN_VERSION: String = "7.17.0"
|
|
54
54
|
static let updateUrlDefault = "https://plugin.capgo.app/updates"
|
|
55
55
|
static let statsUrlDefault = "https://plugin.capgo.app/stats"
|
|
56
56
|
static let channelUrlDefault = "https://plugin.capgo.app/channel_self"
|
|
@@ -248,6 +248,13 @@ public class CapacitorUpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
248
248
|
logger.error("Delete failed, id \(version.getId()) doesn't exist")
|
|
249
249
|
}
|
|
250
250
|
}
|
|
251
|
+
|
|
252
|
+
let storedBundles = implementation.list(raw: true)
|
|
253
|
+
let allowedIds = Set(storedBundles.compactMap { info -> String? in
|
|
254
|
+
let id = info.getId()
|
|
255
|
+
return id.isEmpty ? nil : id
|
|
256
|
+
})
|
|
257
|
+
implementation.cleanupDownloadDirectories(allowedIds: allowedIds)
|
|
251
258
|
}
|
|
252
259
|
UserDefaults.standard.set(self.currentBuildVersion, forKey: "LatestNativeBuildVersion")
|
|
253
260
|
UserDefaults.standard.synchronize()
|
|
@@ -875,10 +882,17 @@ public class CapacitorUpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
875
882
|
}
|
|
876
883
|
}
|
|
877
884
|
|
|
878
|
-
func endBackGroundTaskWithNotif(
|
|
885
|
+
func endBackGroundTaskWithNotif(
|
|
886
|
+
msg: String,
|
|
887
|
+
latestVersionName: String,
|
|
888
|
+
current: BundleInfo,
|
|
889
|
+
error: Bool = true,
|
|
890
|
+
failureAction: String = "download_fail",
|
|
891
|
+
failureEvent: String = "downloadFailed"
|
|
892
|
+
) {
|
|
879
893
|
if error {
|
|
880
|
-
self.implementation.sendStats(action:
|
|
881
|
-
self.notifyListeners(
|
|
894
|
+
self.implementation.sendStats(action: failureAction, versionName: current.getVersionName())
|
|
895
|
+
self.notifyListeners(failureEvent, data: ["version": latestVersionName])
|
|
882
896
|
}
|
|
883
897
|
self.notifyListeners("noNeedUpdate", data: ["bundle": current.toJSON()])
|
|
884
898
|
self.sendReadyToJs(current: current, msg: msg)
|
|
@@ -903,18 +917,41 @@ public class CapacitorUpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
903
917
|
let current = self.implementation.getCurrentBundle()
|
|
904
918
|
|
|
905
919
|
// Handle network errors and other failures first
|
|
906
|
-
if res.error
|
|
907
|
-
self.logger.error("getLatest failed with error: \(
|
|
908
|
-
|
|
920
|
+
if let backendError = res.error, !backendError.isEmpty {
|
|
921
|
+
self.logger.error("getLatest failed with error: \(backendError)")
|
|
922
|
+
if backendError == "response_error" {
|
|
923
|
+
self.endBackGroundTaskWithNotif(
|
|
924
|
+
msg: "Network error: \(backendError)",
|
|
925
|
+
latestVersionName: res.version,
|
|
926
|
+
current: current,
|
|
927
|
+
error: true
|
|
928
|
+
)
|
|
929
|
+
} else {
|
|
930
|
+
self.endBackGroundTaskWithNotif(
|
|
931
|
+
msg: backendError,
|
|
932
|
+
latestVersionName: res.version,
|
|
933
|
+
current: current,
|
|
934
|
+
error: true,
|
|
935
|
+
failureAction: "backend_refusal",
|
|
936
|
+
failureEvent: "backendRefused"
|
|
937
|
+
)
|
|
938
|
+
}
|
|
909
939
|
return
|
|
910
940
|
}
|
|
911
941
|
|
|
912
|
-
if
|
|
913
|
-
self.logger.info("API message: \(
|
|
942
|
+
if let message = res.message, !message.isEmpty {
|
|
943
|
+
self.logger.info("API message: \(message)")
|
|
914
944
|
if res.major == true {
|
|
915
945
|
self.notifyListeners("majorAvailable", data: ["version": res.version])
|
|
916
946
|
}
|
|
917
|
-
self.endBackGroundTaskWithNotif(
|
|
947
|
+
self.endBackGroundTaskWithNotif(
|
|
948
|
+
msg: message,
|
|
949
|
+
latestVersionName: res.version,
|
|
950
|
+
current: current,
|
|
951
|
+
error: true,
|
|
952
|
+
failureAction: "backend_refusal",
|
|
953
|
+
failureEvent: "backendRefused"
|
|
954
|
+
)
|
|
918
955
|
return
|
|
919
956
|
}
|
|
920
957
|
if res.version == "builtin" {
|
|
@@ -886,6 +886,42 @@ import UIKit
|
|
|
886
886
|
return self.delete(id: id, removeInfo: true)
|
|
887
887
|
}
|
|
888
888
|
|
|
889
|
+
public func cleanupDownloadDirectories(allowedIds: Set<String>) {
|
|
890
|
+
let bundleRoot = libraryDir.appendingPathComponent(bundleDirectory)
|
|
891
|
+
let fileManager = FileManager.default
|
|
892
|
+
|
|
893
|
+
guard fileManager.fileExists(atPath: bundleRoot.path) else {
|
|
894
|
+
return
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
do {
|
|
898
|
+
let contents = try fileManager.contentsOfDirectory(at: bundleRoot, includingPropertiesForKeys: [.isDirectoryKey], options: [.skipsHiddenFiles])
|
|
899
|
+
|
|
900
|
+
for url in contents {
|
|
901
|
+
let resourceValues = try url.resourceValues(forKeys: [.isDirectoryKey])
|
|
902
|
+
if resourceValues.isDirectory != true {
|
|
903
|
+
continue
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
let id = url.lastPathComponent
|
|
907
|
+
|
|
908
|
+
if allowedIds.contains(id) {
|
|
909
|
+
continue
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
do {
|
|
913
|
+
try fileManager.removeItem(at: url)
|
|
914
|
+
self.removeBundleInfo(id: id)
|
|
915
|
+
logger.info("Deleted orphan bundle directory: \(id)")
|
|
916
|
+
} catch {
|
|
917
|
+
logger.error("Failed to delete orphan bundle directory: \(id) \(error.localizedDescription)")
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
} catch {
|
|
921
|
+
logger.error("Failed to enumerate bundle directory for cleanup: \(error.localizedDescription)")
|
|
922
|
+
}
|
|
923
|
+
}
|
|
924
|
+
|
|
889
925
|
public func getBundleDirectory(id: String) -> URL {
|
|
890
926
|
return libraryDir.appendingPathComponent(self.bundleDirectory).appendingPathComponent(id)
|
|
891
927
|
}
|