@capgo/capacitor-updater 8.47.5 → 8.47.6
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 +207 -41
- package/android/src/main/java/ee/forgr/capacitor_updater/CapgoUpdater.java +278 -260
- package/android/src/main/java/ee/forgr/capacitor_updater/DownloadService.java +23 -26
- package/android/src/main/java/ee/forgr/capacitor_updater/ShakeMenu.java +45 -52
- package/ios/Sources/CapacitorUpdaterPlugin/CapacitorUpdaterPlugin.swift +162 -11
- package/package.json +1 -1
|
@@ -115,15 +115,13 @@ public class DownloadService extends Worker {
|
|
|
115
115
|
}
|
|
116
116
|
|
|
117
117
|
StringBuilder sanitized = new StringBuilder();
|
|
118
|
-
value
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
}
|
|
126
|
-
});
|
|
118
|
+
value.codePoints().forEach((cp) -> {
|
|
119
|
+
boolean isVisibleAscii = cp >= 0x20 && cp <= 0x7E;
|
|
120
|
+
boolean isIso88591 = cp >= 0xA0 && cp <= 0xFF;
|
|
121
|
+
if (isVisibleAscii || isIso88591) {
|
|
122
|
+
sanitized.appendCodePoint(cp);
|
|
123
|
+
}
|
|
124
|
+
});
|
|
127
125
|
|
|
128
126
|
String result = sanitized.toString().trim();
|
|
129
127
|
return result.isEmpty() ? "unknown" : result;
|
|
@@ -255,27 +253,26 @@ public class DownloadService extends Worker {
|
|
|
255
253
|
.post(RequestBody.create(json.toString(), MediaType.get("application/json")))
|
|
256
254
|
.build();
|
|
257
255
|
|
|
258
|
-
sharedClient
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
if (logger != null) {
|
|
265
|
-
logger.error("Failed to send stats: " + e.getMessage());
|
|
266
|
-
}
|
|
256
|
+
sharedClient.newCall(request).enqueue(
|
|
257
|
+
new Callback() {
|
|
258
|
+
@Override
|
|
259
|
+
public void onFailure(@NonNull Call call, @NonNull IOException e) {
|
|
260
|
+
if (logger != null) {
|
|
261
|
+
logger.error("Failed to send stats: " + e.getMessage());
|
|
267
262
|
}
|
|
263
|
+
}
|
|
268
264
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
265
|
+
@Override
|
|
266
|
+
public void onResponse(@NonNull Call call, @NonNull Response response) {
|
|
267
|
+
try (ResponseBody body = response.body()) {
|
|
268
|
+
// nothing else to do, just closing body
|
|
269
|
+
} catch (Exception ignored) {
|
|
270
|
+
} finally {
|
|
271
|
+
response.close();
|
|
276
272
|
}
|
|
277
273
|
}
|
|
278
|
-
|
|
274
|
+
}
|
|
275
|
+
);
|
|
279
276
|
} catch (Exception e) {
|
|
280
277
|
if (logger != null) {
|
|
281
278
|
logger.error("sendStatsAsync error: " + e.getMessage());
|
|
@@ -111,49 +111,43 @@ public class ShakeMenu implements ShakeDetector.Listener {
|
|
|
111
111
|
AlertDialog dialog = builder.create();
|
|
112
112
|
dialog.setOnDismissListener((dialogInterface) -> isShowing = false);
|
|
113
113
|
dialog.show();
|
|
114
|
-
dialog
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
if (!plugin.leavePreviewSessionFromShakeMenu()) {
|
|
121
|
-
activity.runOnUiThread(() -> showError("Could not leave the test app."));
|
|
122
|
-
}
|
|
123
|
-
} catch (Exception e) {
|
|
124
|
-
logger.error("Error leaving test app: " + e.getMessage());
|
|
125
|
-
activity.runOnUiThread(() -> showError("Error leaving test app: " + e.getMessage()));
|
|
126
|
-
} finally {
|
|
127
|
-
activity.runOnUiThread(() -> {
|
|
128
|
-
dialog.dismiss();
|
|
129
|
-
isShowing = false;
|
|
130
|
-
});
|
|
114
|
+
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener((view) -> {
|
|
115
|
+
setPreviewMenuButtonsEnabled(dialog, false);
|
|
116
|
+
new Thread(() -> {
|
|
117
|
+
try {
|
|
118
|
+
if (!plugin.leavePreviewSessionFromShakeMenu()) {
|
|
119
|
+
activity.runOnUiThread(() -> showError("Could not leave the test app."));
|
|
131
120
|
}
|
|
132
|
-
})
|
|
133
|
-
.
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
activity.runOnUiThread(() ->
|
|
150
|
-
dialog.dismiss();
|
|
151
|
-
isShowing = false;
|
|
152
|
-
});
|
|
121
|
+
} catch (Exception e) {
|
|
122
|
+
logger.error("Error leaving test app: " + e.getMessage());
|
|
123
|
+
activity.runOnUiThread(() -> showError("Error leaving test app: " + e.getMessage()));
|
|
124
|
+
} finally {
|
|
125
|
+
activity.runOnUiThread(() -> {
|
|
126
|
+
dialog.dismiss();
|
|
127
|
+
isShowing = false;
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
}).start();
|
|
131
|
+
});
|
|
132
|
+
dialog.getButton(AlertDialog.BUTTON_NEUTRAL).setOnClickListener((view) -> {
|
|
133
|
+
setPreviewMenuButtonsEnabled(dialog, false);
|
|
134
|
+
new Thread(() -> {
|
|
135
|
+
try {
|
|
136
|
+
logger.info("Reloading webview");
|
|
137
|
+
if (!plugin.reloadPreviewSessionFromShakeMenu()) {
|
|
138
|
+
activity.runOnUiThread(() -> showError("Could not reload the test app."));
|
|
153
139
|
}
|
|
154
|
-
})
|
|
155
|
-
.
|
|
156
|
-
|
|
140
|
+
} catch (Exception e) {
|
|
141
|
+
logger.error("Error in Reload action: " + e.getMessage());
|
|
142
|
+
activity.runOnUiThread(() -> showError("Error reloading test app: " + e.getMessage()));
|
|
143
|
+
} finally {
|
|
144
|
+
activity.runOnUiThread(() -> {
|
|
145
|
+
dialog.dismiss();
|
|
146
|
+
isShowing = false;
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
}).start();
|
|
150
|
+
});
|
|
157
151
|
} catch (Exception e) {
|
|
158
152
|
logger.error("Error showing shake menu: " + e.getMessage());
|
|
159
153
|
isShowing = false;
|
|
@@ -351,8 +345,7 @@ public class ShakeMenu implements ShakeDetector.Listener {
|
|
|
351
345
|
presentChannelPicker(channels);
|
|
352
346
|
});
|
|
353
347
|
});
|
|
354
|
-
})
|
|
355
|
-
.start();
|
|
348
|
+
}).start();
|
|
356
349
|
} catch (Exception e) {
|
|
357
350
|
logger.error("Error showing channel selector: " + e.getMessage());
|
|
358
351
|
isShowing = false;
|
|
@@ -543,13 +536,14 @@ public class ShakeMenu implements ShakeDetector.Listener {
|
|
|
543
536
|
String latestKind = getString(latestRes, "kind");
|
|
544
537
|
String latestMessage = getString(latestRes, "message");
|
|
545
538
|
|
|
546
|
-
String detail =
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
539
|
+
String detail =
|
|
540
|
+
latestMessage != null && !latestMessage.isEmpty()
|
|
541
|
+
? latestMessage
|
|
542
|
+
: latestError != null && !latestError.isEmpty()
|
|
543
|
+
? latestError
|
|
544
|
+
: latestKind != null && !latestKind.isEmpty()
|
|
545
|
+
? latestKind
|
|
546
|
+
: "server did not provide a message";
|
|
553
547
|
|
|
554
548
|
// Handle update errors first (before "no new version" check)
|
|
555
549
|
if (
|
|
@@ -668,8 +662,7 @@ public class ShakeMenu implements ShakeDetector.Listener {
|
|
|
668
662
|
});
|
|
669
663
|
}
|
|
670
664
|
);
|
|
671
|
-
})
|
|
672
|
-
.start();
|
|
665
|
+
}).start();
|
|
673
666
|
} catch (Exception e) {
|
|
674
667
|
logger.error("Error selecting channel: " + e.getMessage());
|
|
675
668
|
isShowing = false;
|
|
@@ -79,7 +79,7 @@ public class CapacitorUpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
79
79
|
CAPPluginMethod(name: "completeFlexibleUpdate", returnType: CAPPluginReturnPromise)
|
|
80
80
|
]
|
|
81
81
|
public var implementation = CapgoUpdater()
|
|
82
|
-
private let pluginVersion: String = "8.47.
|
|
82
|
+
private let pluginVersion: String = "8.47.6"
|
|
83
83
|
static let updateUrlDefault = "https://plugin.capgo.app/updates"
|
|
84
84
|
static let statsUrlDefault = "https://plugin.capgo.app/stats"
|
|
85
85
|
static let channelUrlDefault = "https://plugin.capgo.app/channel_self"
|
|
@@ -165,6 +165,7 @@ public class CapacitorUpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
165
165
|
public var previewSessionEnabled = false
|
|
166
166
|
private var previewSessionAlertPending = false
|
|
167
167
|
private var isLeavingPreviewForIncomingLink = false
|
|
168
|
+
private var previewTransitionClearWorkItem: DispatchWorkItem?
|
|
168
169
|
let semaphoreReady = DispatchSemaphore(value: 0)
|
|
169
170
|
|
|
170
171
|
private var delayUpdateUtils: DelayUpdateUtils!
|
|
@@ -986,7 +987,10 @@ public class CapacitorUpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
986
987
|
let current: BundleInfo = self.implementation.getCurrentBundle()
|
|
987
988
|
let next: BundleInfo? = self.implementation.getNextBundle()
|
|
988
989
|
|
|
989
|
-
if
|
|
990
|
+
if !self.isPreviewSessionStateActive(),
|
|
991
|
+
let next = next,
|
|
992
|
+
!next.isErrorStatus(),
|
|
993
|
+
next.getId() != current.getId() {
|
|
990
994
|
let previousState = self.implementation.captureResetState()
|
|
991
995
|
let previousBundleName = self.implementation.getCurrentBundle().getVersionName()
|
|
992
996
|
logger.info("Applying pending bundle before reload: \(next.toString())")
|
|
@@ -1025,6 +1029,28 @@ public class CapacitorUpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
1025
1029
|
}
|
|
1026
1030
|
}
|
|
1027
1031
|
|
|
1032
|
+
private func applyDownloadedBundleForDirectUpdate(_ next: BundleInfo) -> Bool {
|
|
1033
|
+
let previousState = self.implementation.captureResetState()
|
|
1034
|
+
let previousBundleName = self.implementation.getCurrentBundle().getVersionName()
|
|
1035
|
+
|
|
1036
|
+
guard self.implementation.stagePendingReload(bundle: next) else {
|
|
1037
|
+
self.implementation.restoreResetState(previousState)
|
|
1038
|
+
logger.error("Direct update failed to stage downloaded bundle: \(next.toString())")
|
|
1039
|
+
return false
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
if self._reload() {
|
|
1043
|
+
self.implementation.finalizePendingReload(bundle: next, previousBundleName: previousBundleName)
|
|
1044
|
+
_ = self.implementation.setNextBundle(next: Optional<String>.none)
|
|
1045
|
+
return true
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
self.implementation.restoreResetState(previousState)
|
|
1049
|
+
self.restoreLiveBundleStateAfterFailedReload()
|
|
1050
|
+
logger.error("Direct update reload failed after staging bundle: \(next.toString())")
|
|
1051
|
+
return false
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1028
1054
|
@objc func next(_ call: CAPPluginCall) {
|
|
1029
1055
|
guard let id = call.getString("id") else {
|
|
1030
1056
|
logger.error("Next called without id")
|
|
@@ -1060,6 +1086,37 @@ public class CapacitorUpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
1060
1086
|
}
|
|
1061
1087
|
}
|
|
1062
1088
|
|
|
1089
|
+
private func isPreviewSessionStateActive() -> Bool {
|
|
1090
|
+
self.previewSessionEnabled || self.isLeavingPreviewForIncomingLink || self.implementation.previewSession
|
|
1091
|
+
}
|
|
1092
|
+
|
|
1093
|
+
private func shouldBlockAutoUpdateForPreviewSession() -> Bool {
|
|
1094
|
+
guard self.isPreviewSessionStateActive() else {
|
|
1095
|
+
return false
|
|
1096
|
+
}
|
|
1097
|
+
|
|
1098
|
+
logger.info("Preview session is active. Skipping normal auto-update work.")
|
|
1099
|
+
return true
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1102
|
+
private func clearIncomingPreviewTransition() {
|
|
1103
|
+
self.previewTransitionClearWorkItem?.cancel()
|
|
1104
|
+
self.previewTransitionClearWorkItem = nil
|
|
1105
|
+
self.isLeavingPreviewForIncomingLink = false
|
|
1106
|
+
if !self.previewSessionEnabled {
|
|
1107
|
+
self.implementation.previewSession = false
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
private func scheduleIncomingPreviewTransitionFallbackClear() {
|
|
1112
|
+
self.previewTransitionClearWorkItem?.cancel()
|
|
1113
|
+
let workItem = DispatchWorkItem { [weak self] in
|
|
1114
|
+
self?.clearIncomingPreviewTransition()
|
|
1115
|
+
}
|
|
1116
|
+
self.previewTransitionClearWorkItem = workItem
|
|
1117
|
+
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(self.appReadyTimeout), execute: workItem)
|
|
1118
|
+
}
|
|
1119
|
+
|
|
1063
1120
|
@objc func startPreviewSession(_ call: CAPPluginCall) {
|
|
1064
1121
|
guard self.allowPreview else {
|
|
1065
1122
|
logger.error("startPreviewSession called without allowPreview")
|
|
@@ -1117,6 +1174,7 @@ public class CapacitorUpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
1117
1174
|
UserDefaults.standard.removeObject(forKey: self.previewPayloadUrlDefaultsKey)
|
|
1118
1175
|
}
|
|
1119
1176
|
|
|
1177
|
+
self.clearIncomingPreviewTransition()
|
|
1120
1178
|
self.previewSessionEnabled = true
|
|
1121
1179
|
self.previewSessionAlertPending = true
|
|
1122
1180
|
self.implementation.previewSession = true
|
|
@@ -1159,7 +1217,7 @@ public class CapacitorUpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
1159
1217
|
}
|
|
1160
1218
|
}
|
|
1161
1219
|
|
|
1162
|
-
private func leavePreviewSessionWithoutReload() -> Bool {
|
|
1220
|
+
private func leavePreviewSessionWithoutReload(keepPreviewGuard: Bool = false) -> Bool {
|
|
1163
1221
|
let previewBundle = self.implementation.getCurrentBundle()
|
|
1164
1222
|
guard let previewFallbackBundle = self.implementation.getPreviewFallbackBundle(), !previewFallbackBundle.isErrorStatus() else {
|
|
1165
1223
|
logger.error("No preview fallback bundle available")
|
|
@@ -1174,12 +1232,50 @@ public class CapacitorUpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
1174
1232
|
return false
|
|
1175
1233
|
}
|
|
1176
1234
|
|
|
1177
|
-
self.endPreviewSession()
|
|
1235
|
+
self.endPreviewSession(keepPreviewGuard: keepPreviewGuard)
|
|
1178
1236
|
let restoredNextBundle = self.implementation.getNextBundle()
|
|
1179
1237
|
self.deletePreviewBundleIfUnused(previewBundle, previewFallbackBundle: previewFallbackBundle, restoredNextBundle: restoredNextBundle)
|
|
1180
1238
|
return true
|
|
1181
1239
|
}
|
|
1182
1240
|
|
|
1241
|
+
private func leavePreviewSessionForIncomingPreviewLink() -> Bool {
|
|
1242
|
+
let previewBundle = self.implementation.getCurrentBundle()
|
|
1243
|
+
guard let previewFallbackBundle = self.implementation.getPreviewFallbackBundle(), !previewFallbackBundle.isErrorStatus() else {
|
|
1244
|
+
logger.error("No preview fallback bundle available")
|
|
1245
|
+
self.clearIncomingPreviewTransition()
|
|
1246
|
+
return false
|
|
1247
|
+
}
|
|
1248
|
+
guard self.implementation.canSet(bundle: previewFallbackBundle) else {
|
|
1249
|
+
logger.error("Preview fallback bundle is not installable")
|
|
1250
|
+
self.clearIncomingPreviewTransition()
|
|
1251
|
+
return false
|
|
1252
|
+
}
|
|
1253
|
+
|
|
1254
|
+
let previousState = self.implementation.captureResetState()
|
|
1255
|
+
guard self.implementation.stagePreviewFallbackReload(bundle: previewFallbackBundle) else {
|
|
1256
|
+
logger.error("Could not stage preview fallback bundle")
|
|
1257
|
+
self.clearIncomingPreviewTransition()
|
|
1258
|
+
return false
|
|
1259
|
+
}
|
|
1260
|
+
|
|
1261
|
+
let didReload = self._reload()
|
|
1262
|
+
if didReload {
|
|
1263
|
+
self.endPreviewSession(keepPreviewGuard: true)
|
|
1264
|
+
let restoredNextBundle = self.implementation.getNextBundle()
|
|
1265
|
+
self.deletePreviewBundleIfUnused(
|
|
1266
|
+
previewBundle,
|
|
1267
|
+
previewFallbackBundle: previewFallbackBundle,
|
|
1268
|
+
restoredNextBundle: restoredNextBundle
|
|
1269
|
+
)
|
|
1270
|
+
self.scheduleIncomingPreviewTransitionFallbackClear()
|
|
1271
|
+
} else {
|
|
1272
|
+
self.implementation.restoreResetState(previousState)
|
|
1273
|
+
self.restoreLiveBundleStateAfterFailedReload()
|
|
1274
|
+
self.clearIncomingPreviewTransition()
|
|
1275
|
+
}
|
|
1276
|
+
return didReload
|
|
1277
|
+
}
|
|
1278
|
+
|
|
1183
1279
|
private func deletePreviewBundleIfUnused(
|
|
1184
1280
|
_ previewBundle: BundleInfo,
|
|
1185
1281
|
previewFallbackBundle: BundleInfo?,
|
|
@@ -1228,7 +1324,7 @@ public class CapacitorUpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
1228
1324
|
return false
|
|
1229
1325
|
}
|
|
1230
1326
|
|
|
1231
|
-
private func endPreviewSession() {
|
|
1327
|
+
private func endPreviewSession(keepPreviewGuard: Bool = false) {
|
|
1232
1328
|
let previousShakeMenuEnabled = UserDefaults.standard.object(forKey: self.previewPreviousShakeMenuDefaultsKey) as? Bool
|
|
1233
1329
|
?? getConfig().getBoolean("shakeMenu", false)
|
|
1234
1330
|
let previousShakeChannelSelectorEnabled = UserDefaults.standard.object(forKey: self.previewPreviousShakeChannelSelectorDefaultsKey) as? Bool
|
|
@@ -1239,8 +1335,11 @@ public class CapacitorUpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
1239
1335
|
|
|
1240
1336
|
self.previewSessionEnabled = false
|
|
1241
1337
|
self.previewSessionAlertPending = false
|
|
1242
|
-
|
|
1243
|
-
|
|
1338
|
+
if keepPreviewGuard {
|
|
1339
|
+
self.implementation.previewSession = true
|
|
1340
|
+
} else {
|
|
1341
|
+
self.clearIncomingPreviewTransition()
|
|
1342
|
+
}
|
|
1244
1343
|
self.shakeMenuEnabled = previousShakeMenuEnabled
|
|
1245
1344
|
self.shakeChannelSelectorEnabled = previousShakeChannelSelectorEnabled
|
|
1246
1345
|
_ = self.implementation.setPreviewFallbackBundle(fallback: nil)
|
|
@@ -1395,7 +1494,7 @@ public class CapacitorUpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
1395
1494
|
self.isLeavingPreviewForIncomingLink = true
|
|
1396
1495
|
logger.info("Preview deeplink received while preview session is active; restoring fallback before routing")
|
|
1397
1496
|
DispatchQueue.global(qos: .userInitiated).async {
|
|
1398
|
-
let didLeave = self.
|
|
1497
|
+
let didLeave = self.leavePreviewSessionForIncomingPreviewLink()
|
|
1399
1498
|
if !didLeave {
|
|
1400
1499
|
self.logger.error("Could not leave preview session before routing incoming preview deeplink")
|
|
1401
1500
|
self.isLeavingPreviewForIncomingLink = false
|
|
@@ -1701,6 +1800,9 @@ public class CapacitorUpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
1701
1800
|
logger.error("Error no url or wrong format")
|
|
1702
1801
|
return "unavailable"
|
|
1703
1802
|
}
|
|
1803
|
+
if self.shouldBlockAutoUpdateForPreviewSession() {
|
|
1804
|
+
return "preview_session"
|
|
1805
|
+
}
|
|
1704
1806
|
if self.isDownloadStuckOrTimedOut() {
|
|
1705
1807
|
logger.info("Download already in progress, skipping duplicate download request")
|
|
1706
1808
|
return "already_running"
|
|
@@ -1937,6 +2039,7 @@ public class CapacitorUpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
1937
2039
|
let bundle = self.implementation.getCurrentBundle()
|
|
1938
2040
|
self.implementation.setSuccess(bundle: bundle, autoDeletePrevious: self.autoDeletePrevious)
|
|
1939
2041
|
logger.info("Current bundle loaded successfully. [notifyAppReady was called] \(bundle.toString())")
|
|
2042
|
+
self.clearIncomingPreviewTransition()
|
|
1940
2043
|
|
|
1941
2044
|
call.resolve(["bundle": bundle.toJSON()])
|
|
1942
2045
|
}
|
|
@@ -1987,6 +2090,9 @@ public class CapacitorUpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
1987
2090
|
// Note: _checkCancelDelay method has been moved to DelayUpdateUtils class
|
|
1988
2091
|
|
|
1989
2092
|
private func _isAutoUpdateEnabled() -> Bool {
|
|
2093
|
+
if self.isPreviewSessionStateActive() {
|
|
2094
|
+
return false
|
|
2095
|
+
}
|
|
1990
2096
|
let instanceDescriptor = (self.bridge?.viewController as? CAPBridgeViewController)?.instanceDescriptor()
|
|
1991
2097
|
if instanceDescriptor?.serverURL != nil {
|
|
1992
2098
|
logger.warn("AutoUpdate is automatic disabled when serverUrl is set.")
|
|
@@ -2024,6 +2130,10 @@ public class CapacitorUpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
2024
2130
|
logger.info("Built-in bundle is active. We skip the check for notifyAppReady.")
|
|
2025
2131
|
return
|
|
2026
2132
|
}
|
|
2133
|
+
if self.isPreviewSessionStateActive() {
|
|
2134
|
+
logger.info("Preview session is active. We skip the check for notifyAppReady.")
|
|
2135
|
+
return
|
|
2136
|
+
}
|
|
2027
2137
|
|
|
2028
2138
|
logger.info("Current bundle is: \(current.toString())")
|
|
2029
2139
|
|
|
@@ -2693,6 +2803,13 @@ public class CapacitorUpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
2693
2803
|
return true
|
|
2694
2804
|
}
|
|
2695
2805
|
|
|
2806
|
+
private func clearDownloadInProgressState() {
|
|
2807
|
+
downloadLock.lock()
|
|
2808
|
+
defer { downloadLock.unlock() }
|
|
2809
|
+
downloadInProgress = false
|
|
2810
|
+
downloadStartTime = nil
|
|
2811
|
+
}
|
|
2812
|
+
|
|
2696
2813
|
func runBackgroundDownloadWork(_ work: @escaping () -> Void) {
|
|
2697
2814
|
// Live update checks/downloads are user-visible work. Using `.background`
|
|
2698
2815
|
// lets the scheduler starve them for minutes while the app is active.
|
|
@@ -2718,6 +2835,9 @@ public class CapacitorUpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
2718
2835
|
}
|
|
2719
2836
|
|
|
2720
2837
|
func backgroundDownload() {
|
|
2838
|
+
if self.shouldBlockAutoUpdateForPreviewSession() {
|
|
2839
|
+
return
|
|
2840
|
+
}
|
|
2721
2841
|
// Set download in progress flag (thread-safe)
|
|
2722
2842
|
downloadLock.lock()
|
|
2723
2843
|
downloadInProgress = true
|
|
@@ -2746,10 +2866,19 @@ public class CapacitorUpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
2746
2866
|
self.runBackgroundDownloadWork {
|
|
2747
2867
|
// Wait for cleanup to complete before starting download
|
|
2748
2868
|
self.waitForCleanupIfNeeded()
|
|
2869
|
+
if self.shouldBlockAutoUpdateForPreviewSession() {
|
|
2870
|
+
self.clearDownloadInProgressState()
|
|
2871
|
+
return
|
|
2872
|
+
}
|
|
2749
2873
|
self.beginDownloadBackgroundTask()
|
|
2750
2874
|
self.logger.info("Check for update via \(self.updateUrl)")
|
|
2751
2875
|
let res = self.implementation.getLatest(url: url, channel: nil)
|
|
2752
2876
|
let current = self.implementation.getCurrentBundle()
|
|
2877
|
+
if self.shouldBlockAutoUpdateForPreviewSession() {
|
|
2878
|
+
self.clearDownloadInProgressState()
|
|
2879
|
+
self.endBackGroundTask()
|
|
2880
|
+
return
|
|
2881
|
+
}
|
|
2753
2882
|
|
|
2754
2883
|
// Handle network errors and other failures first
|
|
2755
2884
|
let backendError = res.error ?? ""
|
|
@@ -2861,6 +2990,11 @@ public class CapacitorUpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
2861
2990
|
)
|
|
2862
2991
|
return
|
|
2863
2992
|
}
|
|
2993
|
+
if self.shouldBlockAutoUpdateForPreviewSession() {
|
|
2994
|
+
self.clearDownloadInProgressState()
|
|
2995
|
+
self.endBackGroundTask()
|
|
2996
|
+
return
|
|
2997
|
+
}
|
|
2864
2998
|
res.checksum = try CryptoCipher.decryptChecksum(checksum: res.checksum, publicKey: self.implementation.publicKey)
|
|
2865
2999
|
CryptoCipher.logChecksumInfo(label: "Bundle checksum", hexChecksum: next.getChecksum())
|
|
2866
3000
|
CryptoCipher.logChecksumInfo(label: "Expected checksum", hexChecksum: res.checksum)
|
|
@@ -2880,6 +3014,11 @@ public class CapacitorUpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
2880
3014
|
)
|
|
2881
3015
|
return
|
|
2882
3016
|
}
|
|
3017
|
+
if self.shouldBlockAutoUpdateForPreviewSession() {
|
|
3018
|
+
self.clearDownloadInProgressState()
|
|
3019
|
+
self.endBackGroundTask()
|
|
3020
|
+
return
|
|
3021
|
+
}
|
|
2883
3022
|
let directUpdateAllowed = plannedDirectUpdate && !self.autoSplashscreenTimedOut
|
|
2884
3023
|
if directUpdateAllowed {
|
|
2885
3024
|
let delayUpdatePreferences = UserDefaults.standard.string(forKey: DelayUpdateUtils.DELAY_CONDITION_PREFERENCES) ?? "[]"
|
|
@@ -2899,7 +3038,7 @@ public class CapacitorUpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
2899
3038
|
)
|
|
2900
3039
|
return
|
|
2901
3040
|
}
|
|
2902
|
-
if self.
|
|
3041
|
+
if self.applyDownloadedBundleForDirectUpdate(next) {
|
|
2903
3042
|
self.notifyBundleSet(next)
|
|
2904
3043
|
self.endBackGroundTaskWithNotif(
|
|
2905
3044
|
msg: "update installed",
|
|
@@ -2909,10 +3048,13 @@ public class CapacitorUpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
2909
3048
|
plannedDirectUpdate: plannedDirectUpdate
|
|
2910
3049
|
)
|
|
2911
3050
|
} else {
|
|
3051
|
+
_ = self.implementation.setNextBundle(next: next.getId())
|
|
3052
|
+
self.notifyListeners("updateAvailable", data: ["bundle": next.toJSON()])
|
|
2912
3053
|
self.endBackGroundTaskWithNotif(
|
|
2913
|
-
msg: "
|
|
3054
|
+
msg: "Direct update reload failed, update will install next background",
|
|
2914
3055
|
latestVersionName: latestVersionName,
|
|
2915
|
-
current:
|
|
3056
|
+
current: self.implementation.getCurrentBundle(),
|
|
3057
|
+
error: false,
|
|
2916
3058
|
plannedDirectUpdate: plannedDirectUpdate
|
|
2917
3059
|
)
|
|
2918
3060
|
}
|
|
@@ -2968,6 +3110,9 @@ public class CapacitorUpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
2968
3110
|
}
|
|
2969
3111
|
|
|
2970
3112
|
private func installNext() {
|
|
3113
|
+
if self.shouldBlockAutoUpdateForPreviewSession() {
|
|
3114
|
+
return
|
|
3115
|
+
}
|
|
2971
3116
|
let delayUpdatePreferences = UserDefaults.standard.string(forKey: DelayUpdateUtils.DELAY_CONDITION_PREFERENCES) ?? "[]"
|
|
2972
3117
|
let delayConditionList: [DelayCondition] = fromJsonArr(json: delayUpdatePreferences).map { obj -> DelayCondition in
|
|
2973
3118
|
let kind: String = obj.value(forKey: "kind") as! String
|
|
@@ -3059,8 +3204,14 @@ public class CapacitorUpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
3059
3204
|
return
|
|
3060
3205
|
}
|
|
3061
3206
|
DispatchQueue.global(qos: .utility).async {
|
|
3207
|
+
if self.shouldBlockAutoUpdateForPreviewSession() {
|
|
3208
|
+
return
|
|
3209
|
+
}
|
|
3062
3210
|
let res = self.implementation.getLatest(url: url, channel: nil)
|
|
3063
3211
|
let current = self.implementation.getCurrentBundle()
|
|
3212
|
+
if self.shouldBlockAutoUpdateForPreviewSession() {
|
|
3213
|
+
return
|
|
3214
|
+
}
|
|
3064
3215
|
|
|
3065
3216
|
if res.version != current.getVersionName() {
|
|
3066
3217
|
self.logger.info("New version found: \(res.version)")
|