@capgo/capacitor-updater 8.47.4 → 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 +314 -36
- 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 +317 -13
- package/ios/Sources/CapacitorUpdaterPlugin/ShakeMenu.swift +1 -1
- package/package.json +1 -1
|
@@ -106,6 +106,7 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
106
106
|
private static final String PREVIEW_PREVIOUS_DEFAULT_CHANNEL_WAS_SET_PREF_KEY = "CapacitorUpdater.previewPreviousDefaultChannelWasSet";
|
|
107
107
|
private static final String PREVIEW_APP_ID_PREF_KEY = "CapacitorUpdater.previewAppId";
|
|
108
108
|
private static final String PREVIEW_PAYLOAD_URL_PREF_KEY = "CapacitorUpdater.previewPayloadUrl";
|
|
109
|
+
private static final String PREVIEW_SESSION_ALERT_PENDING_PREF_KEY = "CapacitorUpdater.previewSessionAlertPending";
|
|
109
110
|
private static final String[] BREAKING_EVENT_NAMES = { "breakingAvailable", "majorAvailable" };
|
|
110
111
|
private static final String LAST_FAILED_BUNDLE_PREF_KEY = "CapacitorUpdater.lastFailedBundle";
|
|
111
112
|
private static final String LAST_REPORTED_APP_EXIT_TIMESTAMP_PREF_KEY = "CapacitorUpdater.lastReportedAppExitTimestamp";
|
|
@@ -127,7 +128,7 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
127
128
|
static final int APPLICATION_EXIT_REASON_USER_REQUESTED = 10;
|
|
128
129
|
static final int APPLICATION_EXIT_REASON_DEPENDENCY_DIED = 12;
|
|
129
130
|
|
|
130
|
-
private final String pluginVersion = "8.47.
|
|
131
|
+
private final String pluginVersion = "8.47.6";
|
|
131
132
|
private static final String DELAY_CONDITION_PREFERENCES = "";
|
|
132
133
|
|
|
133
134
|
private SharedPreferences.Editor editor;
|
|
@@ -158,8 +159,9 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
158
159
|
private volatile boolean onLaunchDirectUpdateUsed = false;
|
|
159
160
|
Boolean shakeMenuEnabled = false;
|
|
160
161
|
Boolean shakeChannelSelectorEnabled = false;
|
|
161
|
-
Boolean previewSessionEnabled = false;
|
|
162
|
+
volatile Boolean previewSessionEnabled = false;
|
|
162
163
|
private Boolean previewSessionAlertPending = false;
|
|
164
|
+
private volatile Boolean isLeavingPreviewForIncomingLink = false;
|
|
163
165
|
private Boolean allowManualBundleError = false;
|
|
164
166
|
private Boolean allowPreview = false;
|
|
165
167
|
Boolean allowSetDefaultChannel = true;
|
|
@@ -168,6 +170,30 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
168
170
|
return this.updateUrl;
|
|
169
171
|
}
|
|
170
172
|
|
|
173
|
+
private boolean isPreviewSessionStateActive() {
|
|
174
|
+
return (
|
|
175
|
+
Boolean.TRUE.equals(this.previewSessionEnabled) ||
|
|
176
|
+
Boolean.TRUE.equals(this.isLeavingPreviewForIncomingLink) ||
|
|
177
|
+
(this.implementation != null && this.implementation.previewSession)
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
private boolean shouldBlockAutoUpdateForPreviewSession() {
|
|
182
|
+
if (!this.isPreviewSessionStateActive()) {
|
|
183
|
+
return false;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
logger.info("Preview session is active. Skipping normal auto-update work.");
|
|
187
|
+
return true;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
private void clearIncomingPreviewTransition() {
|
|
191
|
+
this.isLeavingPreviewForIncomingLink = false;
|
|
192
|
+
if (!Boolean.TRUE.equals(this.previewSessionEnabled) && this.implementation != null) {
|
|
193
|
+
this.implementation.previewSession = false;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
171
197
|
// Used for activity-based foreground/background detection on Android < 14
|
|
172
198
|
private Boolean isPreviousMainActivity = true;
|
|
173
199
|
|
|
@@ -502,6 +528,9 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
502
528
|
}
|
|
503
529
|
this.implementation.previewSession = Boolean.TRUE.equals(this.previewSessionEnabled);
|
|
504
530
|
if (Boolean.TRUE.equals(this.previewSessionEnabled)) {
|
|
531
|
+
this.previewSessionAlertPending = this.prefs.contains(PREVIEW_SESSION_ALERT_PENDING_PREF_KEY)
|
|
532
|
+
? this.prefs.getBoolean(PREVIEW_SESSION_ALERT_PENDING_PREF_KEY, false)
|
|
533
|
+
: true;
|
|
505
534
|
final String previewAppId = this.prefs.getString(PREVIEW_APP_ID_PREF_KEY, "");
|
|
506
535
|
if (previewAppId != null && !previewAppId.isEmpty()) {
|
|
507
536
|
this.setActiveAppId(previewAppId);
|
|
@@ -520,6 +549,7 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
520
549
|
if (nativeBuildVersionChanged) {
|
|
521
550
|
this.clearPreviewSessionForNativeBuildChange();
|
|
522
551
|
}
|
|
552
|
+
this.leavePreviewSessionForLaunchIntentIfNeeded();
|
|
523
553
|
this.reportPreviousAppExitReasons();
|
|
524
554
|
this.reportPreviousWebViewRenderProcessGone();
|
|
525
555
|
this.installWebViewStatsReporter();
|
|
@@ -534,6 +564,7 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
534
564
|
this.delayUpdateUtils.checkCancelDelay(DelayUpdateUtils.CancelDelaySource.KILLED);
|
|
535
565
|
|
|
536
566
|
this.checkForUpdateAfterDelay();
|
|
567
|
+
this.showPreviewSessionNoticeIfNeeded();
|
|
537
568
|
|
|
538
569
|
// On Android 14+ (API 34+), topActivity in RecentTaskInfo returns null due to
|
|
539
570
|
// security restrictions (StrandHogg task hijacking mitigations). Use ProcessLifecycleOwner
|
|
@@ -1322,9 +1353,10 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
1322
1353
|
);
|
|
1323
1354
|
}
|
|
1324
1355
|
} else {
|
|
1325
|
-
final boolean enabled =
|
|
1326
|
-
|
|
1327
|
-
|
|
1356
|
+
final boolean enabled =
|
|
1357
|
+
configuredMode != null
|
|
1358
|
+
? "true".equals(configuredMode)
|
|
1359
|
+
: Boolean.TRUE.equals(this.getConfig().getBoolean("autoUpdate", true));
|
|
1328
1360
|
this.autoUpdateMode = enabled
|
|
1329
1361
|
? autoUpdateModeForLegacyDirectUpdateMode(this.resolveLegacyDirectUpdateModeFromConfig())
|
|
1330
1362
|
: AUTO_UPDATE_MODE_OFF;
|
|
@@ -1499,6 +1531,12 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
1499
1531
|
void scheduleDirectUpdateFinish(final BundleInfo latest) {
|
|
1500
1532
|
startNewThread(() -> {
|
|
1501
1533
|
try {
|
|
1534
|
+
if (this.shouldBlockAutoUpdateForPreviewSession()) {
|
|
1535
|
+
logger.info("Skipping direct update install while preview session state is active");
|
|
1536
|
+
this.implementation.directUpdate = false;
|
|
1537
|
+
this.clearBackgroundDownloadState();
|
|
1538
|
+
return;
|
|
1539
|
+
}
|
|
1502
1540
|
Activity currentActivity = this.getActivity();
|
|
1503
1541
|
if (currentActivity != null) {
|
|
1504
1542
|
this.implementation.activity = currentActivity;
|
|
@@ -1513,16 +1551,54 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
1513
1551
|
}
|
|
1514
1552
|
|
|
1515
1553
|
private void directUpdateFinish(final BundleInfo latest) {
|
|
1554
|
+
if (this.shouldBlockAutoUpdateForPreviewSession()) {
|
|
1555
|
+
logger.info("Skipping direct update finish while preview session state is active");
|
|
1556
|
+
this.implementation.directUpdate = false;
|
|
1557
|
+
this.clearBackgroundDownloadState();
|
|
1558
|
+
return;
|
|
1559
|
+
}
|
|
1516
1560
|
if ("onLaunch".equals(this.directUpdateMode)) {
|
|
1517
1561
|
this.onLaunchDirectUpdateUsed = true;
|
|
1518
1562
|
this.implementation.directUpdate = false;
|
|
1519
1563
|
}
|
|
1520
|
-
if (
|
|
1564
|
+
if (this.applyDownloadedBundleForDirectUpdate(latest)) {
|
|
1565
|
+
this.implementation.setNextBundle(null);
|
|
1521
1566
|
this.notifyBundleSet(latest);
|
|
1522
1567
|
sendReadyToJs(latest, "update installed", true);
|
|
1568
|
+
} else {
|
|
1569
|
+
this.implementation.setNextBundle(latest.getId());
|
|
1570
|
+
final JSObject ret = new JSObject();
|
|
1571
|
+
ret.put("bundle", InternalUtils.mapToJSObject(latest.toJSONMap()));
|
|
1572
|
+
this.notifyListeners("updateAvailable", ret);
|
|
1573
|
+
sendReadyToJs(
|
|
1574
|
+
this.implementation.getCurrentBundle(),
|
|
1575
|
+
"Direct update reload failed, update will install next background",
|
|
1576
|
+
false
|
|
1577
|
+
);
|
|
1523
1578
|
}
|
|
1524
1579
|
}
|
|
1525
1580
|
|
|
1581
|
+
private boolean applyDownloadedBundleForDirectUpdate(final BundleInfo latest) {
|
|
1582
|
+
final CapgoUpdater.ResetState previousState = this.implementation.captureResetState();
|
|
1583
|
+
final String previousBundleName = this.implementation.getCurrentBundle().getVersionName();
|
|
1584
|
+
|
|
1585
|
+
if (!this.implementation.stagePendingReload(latest)) {
|
|
1586
|
+
this.implementation.restoreResetState(previousState);
|
|
1587
|
+
logger.error("Direct update failed to stage downloaded bundle: " + latest.toString());
|
|
1588
|
+
return false;
|
|
1589
|
+
}
|
|
1590
|
+
|
|
1591
|
+
if (this._reload()) {
|
|
1592
|
+
this.implementation.finalizePendingReload(latest, previousBundleName);
|
|
1593
|
+
return true;
|
|
1594
|
+
}
|
|
1595
|
+
|
|
1596
|
+
this.implementation.restoreResetState(previousState);
|
|
1597
|
+
this.restoreLiveBundleStateAfterFailedReload();
|
|
1598
|
+
logger.error("Direct update reload failed after staging bundle: " + latest.toString());
|
|
1599
|
+
return false;
|
|
1600
|
+
}
|
|
1601
|
+
|
|
1526
1602
|
private void cleanupObsoleteVersions() {
|
|
1527
1603
|
cleanupThread = startNewThread(() -> {
|
|
1528
1604
|
synchronized (cleanupLock) {
|
|
@@ -2128,6 +2204,15 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
2128
2204
|
return this.semaphoreWait(phase, waitTimeMs);
|
|
2129
2205
|
}
|
|
2130
2206
|
|
|
2207
|
+
protected boolean reloadWithoutWaitingForAppReady() {
|
|
2208
|
+
this.applyCurrentBundleToBridge();
|
|
2209
|
+
|
|
2210
|
+
final long waitTimeMs = this.resolveAppReadyCheckTimeoutMs();
|
|
2211
|
+
this.checkAppReady(waitTimeMs);
|
|
2212
|
+
this.notifyListeners("appReloaded", new JSObject());
|
|
2213
|
+
return true;
|
|
2214
|
+
}
|
|
2215
|
+
|
|
2131
2216
|
@PluginMethod
|
|
2132
2217
|
public void reload(final PluginCall call) {
|
|
2133
2218
|
startNewThread(() -> {
|
|
@@ -2135,7 +2220,7 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
2135
2220
|
final BundleInfo current = this.implementation.getCurrentBundle();
|
|
2136
2221
|
final BundleInfo next = this.implementation.getNextBundle();
|
|
2137
2222
|
|
|
2138
|
-
if (next != null && !next.isErrorStatus() && !next.getId().equals(current.getId())) {
|
|
2223
|
+
if (!this.isPreviewSessionStateActive() && next != null && !next.isErrorStatus() && !next.getId().equals(current.getId())) {
|
|
2139
2224
|
final CapgoUpdater.ResetState previousState = this.implementation.captureResetState();
|
|
2140
2225
|
final String previousBundleName = this.implementation.getCurrentBundle().getVersionName();
|
|
2141
2226
|
logger.info("Applying pending bundle before reload: " + next.getVersionName());
|
|
@@ -2215,6 +2300,12 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
2215
2300
|
if (!this.implementation.set(id)) {
|
|
2216
2301
|
logger.info("No such bundle " + id);
|
|
2217
2302
|
call.reject("Update failed, id " + id + " does not exist.");
|
|
2303
|
+
} else if (Boolean.TRUE.equals(this.previewSessionEnabled)) {
|
|
2304
|
+
logger.info("Preview session set active bundle " + id + " without waiting for preview app readiness");
|
|
2305
|
+
this.reloadWithoutWaitingForAppReady();
|
|
2306
|
+
this.notifyBundleSet(this.implementation.getBundleInfo(id));
|
|
2307
|
+
this.showPreviewSessionNoticeIfNeeded();
|
|
2308
|
+
call.resolve();
|
|
2218
2309
|
} else if (!this._reload()) {
|
|
2219
2310
|
logger.error("Reload failed after setting bundle " + id);
|
|
2220
2311
|
call.reject("Reload failed after setting bundle " + id);
|
|
@@ -2301,6 +2392,7 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
2301
2392
|
this.shakeMenuEnabled = true;
|
|
2302
2393
|
this.shakeChannelSelectorEnabled = false;
|
|
2303
2394
|
this.editor.putBoolean(PREVIEW_SESSION_PREF_KEY, true);
|
|
2395
|
+
this.editor.putBoolean(PREVIEW_SESSION_ALERT_PENDING_PREF_KEY, true);
|
|
2304
2396
|
this.editor.apply();
|
|
2305
2397
|
this.ensureShakeMenuStarted();
|
|
2306
2398
|
call.resolve();
|
|
@@ -2322,6 +2414,97 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
2322
2414
|
final BundleInfo previewFallbackBundle = this.implementation.getPreviewFallbackBundle();
|
|
2323
2415
|
this.endPreviewSession();
|
|
2324
2416
|
final BundleInfo restoredNextBundle = this.implementation.getNextBundle();
|
|
2417
|
+
this.deletePreviewBundleIfUnused(previewBundle, previewFallbackBundle, restoredNextBundle);
|
|
2418
|
+
return true;
|
|
2419
|
+
}
|
|
2420
|
+
|
|
2421
|
+
private boolean leavePreviewSessionForIncomingPreviewLink() {
|
|
2422
|
+
final BundleInfo previewBundle = this.implementation.getCurrentBundle();
|
|
2423
|
+
final BundleInfo previewFallbackBundle = this.implementation.getPreviewFallbackBundle();
|
|
2424
|
+
|
|
2425
|
+
try {
|
|
2426
|
+
if (previewFallbackBundle == null || previewFallbackBundle.isErrorStatus()) {
|
|
2427
|
+
logger.error("No preview fallback bundle available");
|
|
2428
|
+
return false;
|
|
2429
|
+
}
|
|
2430
|
+
if (!this.implementation.canSet(previewFallbackBundle)) {
|
|
2431
|
+
logger.error("Preview fallback bundle is not installable");
|
|
2432
|
+
return false;
|
|
2433
|
+
}
|
|
2434
|
+
|
|
2435
|
+
final CapgoUpdater.ResetState previousState = this.implementation.captureResetState();
|
|
2436
|
+
if (!this.implementation.stagePreviewFallbackReload(previewFallbackBundle)) {
|
|
2437
|
+
logger.error("Could not stage preview fallback bundle");
|
|
2438
|
+
return false;
|
|
2439
|
+
}
|
|
2440
|
+
|
|
2441
|
+
if (!this._reload()) {
|
|
2442
|
+
this.implementation.restoreResetState(previousState);
|
|
2443
|
+
this.restoreLiveBundleStateAfterFailedReload();
|
|
2444
|
+
return false;
|
|
2445
|
+
}
|
|
2446
|
+
|
|
2447
|
+
this.endPreviewSession(true);
|
|
2448
|
+
final BundleInfo restoredNextBundle = this.implementation.getNextBundle();
|
|
2449
|
+
this.deletePreviewBundleIfUnused(previewBundle, previewFallbackBundle, restoredNextBundle);
|
|
2450
|
+
return true;
|
|
2451
|
+
} finally {
|
|
2452
|
+
this.clearIncomingPreviewTransition();
|
|
2453
|
+
}
|
|
2454
|
+
}
|
|
2455
|
+
|
|
2456
|
+
private void leavePreviewSessionForLaunchIntentIfNeeded() {
|
|
2457
|
+
final Intent intent = getActivity() == null ? null : getActivity().getIntent();
|
|
2458
|
+
if (
|
|
2459
|
+
intent == null ||
|
|
2460
|
+
!Intent.ACTION_VIEW.equals(intent.getAction()) ||
|
|
2461
|
+
intent.getData() == null ||
|
|
2462
|
+
!Boolean.TRUE.equals(this.previewSessionEnabled) ||
|
|
2463
|
+
!isPreviewDeepLink(intent.getData()) ||
|
|
2464
|
+
Boolean.TRUE.equals(this.isLeavingPreviewForIncomingLink)
|
|
2465
|
+
) {
|
|
2466
|
+
return;
|
|
2467
|
+
}
|
|
2468
|
+
|
|
2469
|
+
this.isLeavingPreviewForIncomingLink = true;
|
|
2470
|
+
logger.info("Preview deeplink launch detected while preview session is active; restoring fallback before initial load");
|
|
2471
|
+
if (!this.leavePreviewSessionWithoutReload()) {
|
|
2472
|
+
logger.error("Could not leave preview session before initial preview deeplink routing");
|
|
2473
|
+
this.isLeavingPreviewForIncomingLink = false;
|
|
2474
|
+
}
|
|
2475
|
+
}
|
|
2476
|
+
|
|
2477
|
+
private boolean leavePreviewSessionWithoutReload() {
|
|
2478
|
+
return this.leavePreviewSessionWithoutReload(false);
|
|
2479
|
+
}
|
|
2480
|
+
|
|
2481
|
+
private boolean leavePreviewSessionWithoutReload(final boolean keepPreviewGuard) {
|
|
2482
|
+
final BundleInfo previewBundle = this.implementation.getCurrentBundle();
|
|
2483
|
+
final BundleInfo previewFallbackBundle = this.implementation.getPreviewFallbackBundle();
|
|
2484
|
+
if (previewFallbackBundle == null || previewFallbackBundle.isErrorStatus()) {
|
|
2485
|
+
logger.error("No preview fallback bundle available");
|
|
2486
|
+
return false;
|
|
2487
|
+
}
|
|
2488
|
+
if (!this.implementation.canSet(previewFallbackBundle)) {
|
|
2489
|
+
logger.error("Preview fallback bundle is not installable");
|
|
2490
|
+
return false;
|
|
2491
|
+
}
|
|
2492
|
+
if (!this.implementation.stagePreviewFallbackReload(previewFallbackBundle)) {
|
|
2493
|
+
logger.error("Could not stage preview fallback bundle");
|
|
2494
|
+
return false;
|
|
2495
|
+
}
|
|
2496
|
+
|
|
2497
|
+
this.endPreviewSession(keepPreviewGuard);
|
|
2498
|
+
final BundleInfo restoredNextBundle = this.implementation.getNextBundle();
|
|
2499
|
+
this.deletePreviewBundleIfUnused(previewBundle, previewFallbackBundle, restoredNextBundle);
|
|
2500
|
+
return true;
|
|
2501
|
+
}
|
|
2502
|
+
|
|
2503
|
+
private void deletePreviewBundleIfUnused(
|
|
2504
|
+
final BundleInfo previewBundle,
|
|
2505
|
+
final BundleInfo previewFallbackBundle,
|
|
2506
|
+
final BundleInfo restoredNextBundle
|
|
2507
|
+
) {
|
|
2325
2508
|
if (
|
|
2326
2509
|
!previewBundle.isBuiltin() &&
|
|
2327
2510
|
(previewFallbackBundle == null || !previewBundle.getId().equals(previewFallbackBundle.getId())) &&
|
|
@@ -2333,7 +2516,6 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
2333
2516
|
logger.warn("Cannot delete preview bundle " + previewBundle.getId() + ": " + err.getMessage());
|
|
2334
2517
|
}
|
|
2335
2518
|
}
|
|
2336
|
-
return true;
|
|
2337
2519
|
}
|
|
2338
2520
|
|
|
2339
2521
|
public boolean reloadPreviewSessionFromShakeMenu() {
|
|
@@ -2342,7 +2524,7 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
2342
2524
|
return this.refreshPreviewSessionFromPayloadUrl(payloadUrl);
|
|
2343
2525
|
}
|
|
2344
2526
|
|
|
2345
|
-
return this.
|
|
2527
|
+
return this.reloadWithoutWaitingForAppReady();
|
|
2346
2528
|
}
|
|
2347
2529
|
|
|
2348
2530
|
public boolean hasActivePreviewSession() {
|
|
@@ -2374,6 +2556,10 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
2374
2556
|
}
|
|
2375
2557
|
|
|
2376
2558
|
private void endPreviewSession() {
|
|
2559
|
+
this.endPreviewSession(false);
|
|
2560
|
+
}
|
|
2561
|
+
|
|
2562
|
+
private void endPreviewSession(final boolean keepPreviewGuard) {
|
|
2377
2563
|
final boolean previousShakeMenuEnabled = this.prefs.getBoolean(
|
|
2378
2564
|
PREVIEW_PREVIOUS_SHAKE_MENU_PREF_KEY,
|
|
2379
2565
|
this.getConfig().getBoolean("shakeMenu", false)
|
|
@@ -2388,7 +2574,11 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
2388
2574
|
|
|
2389
2575
|
this.previewSessionEnabled = false;
|
|
2390
2576
|
this.previewSessionAlertPending = false;
|
|
2391
|
-
|
|
2577
|
+
if (keepPreviewGuard) {
|
|
2578
|
+
this.implementation.previewSession = true;
|
|
2579
|
+
} else {
|
|
2580
|
+
this.clearIncomingPreviewTransition();
|
|
2581
|
+
}
|
|
2392
2582
|
this.shakeMenuEnabled = previousShakeMenuEnabled;
|
|
2393
2583
|
this.shakeChannelSelectorEnabled = previousShakeChannelSelectorEnabled;
|
|
2394
2584
|
this.implementation.setPreviewFallbackBundle(null);
|
|
@@ -2399,9 +2589,8 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
2399
2589
|
private void clearPreviewSessionBecauseDisabled() {
|
|
2400
2590
|
logger.info("Preview session disabled by config; restoring preview fallback");
|
|
2401
2591
|
final BundleInfo fallback = this.implementation.getPreviewFallbackBundle();
|
|
2402
|
-
final BundleInfo bundleToRestore =
|
|
2403
|
-
? this.implementation.getBundleInfo(BundleInfo.ID_BUILTIN)
|
|
2404
|
-
: fallback;
|
|
2592
|
+
final BundleInfo bundleToRestore =
|
|
2593
|
+
fallback == null || fallback.isErrorStatus() ? this.implementation.getBundleInfo(BundleInfo.ID_BUILTIN) : fallback;
|
|
2405
2594
|
|
|
2406
2595
|
if (this.implementation.canSet(bundleToRestore)) {
|
|
2407
2596
|
this.implementation.stagePreviewFallbackReload(bundleToRestore);
|
|
@@ -2414,6 +2603,7 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
2414
2603
|
this.restorePreviewPreviousDefaultChannel();
|
|
2415
2604
|
this.previewSessionEnabled = false;
|
|
2416
2605
|
this.previewSessionAlertPending = false;
|
|
2606
|
+
this.isLeavingPreviewForIncomingLink = false;
|
|
2417
2607
|
this.implementation.previewSession = false;
|
|
2418
2608
|
this.shakeMenuEnabled = this.getConfig().getBoolean("shakeMenu", false);
|
|
2419
2609
|
this.shakeChannelSelectorEnabled = this.getConfig().getBoolean("allowShakeChannelSelector", false);
|
|
@@ -2433,6 +2623,7 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
2433
2623
|
this.editor.remove(PREVIEW_PREVIOUS_DEFAULT_CHANNEL_WAS_SET_PREF_KEY);
|
|
2434
2624
|
this.editor.remove(PREVIEW_APP_ID_PREF_KEY);
|
|
2435
2625
|
this.editor.remove(PREVIEW_PAYLOAD_URL_PREF_KEY);
|
|
2626
|
+
this.editor.remove(PREVIEW_SESSION_ALERT_PENDING_PREF_KEY);
|
|
2436
2627
|
this.editor.apply();
|
|
2437
2628
|
}
|
|
2438
2629
|
|
|
@@ -2523,6 +2714,21 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
2523
2714
|
return this.normalizePreviewPayloadUrl(this.prefs.getString(PREVIEW_PAYLOAD_URL_PREF_KEY, null));
|
|
2524
2715
|
}
|
|
2525
2716
|
|
|
2717
|
+
private String previewPathFromUri(final Uri uri) {
|
|
2718
|
+
if ("capgo".equals(uri.getScheme())) {
|
|
2719
|
+
final String host = uri.getHost();
|
|
2720
|
+
final String path = uri.getPath();
|
|
2721
|
+
return ("/" + (host == null ? "" : host) + (path == null ? "" : path)).replaceAll("/+", "/");
|
|
2722
|
+
}
|
|
2723
|
+
|
|
2724
|
+
return uri.getPath();
|
|
2725
|
+
}
|
|
2726
|
+
|
|
2727
|
+
private boolean isPreviewDeepLink(final Uri uri) {
|
|
2728
|
+
final String path = this.previewPathFromUri(uri);
|
|
2729
|
+
return "/preview/channel".equals(path) || "/preview/bundle".equals(path);
|
|
2730
|
+
}
|
|
2731
|
+
|
|
2526
2732
|
private String readResponseBody(final InputStream stream) throws IOException {
|
|
2527
2733
|
if (stream == null) {
|
|
2528
2734
|
return "";
|
|
@@ -2593,7 +2799,7 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
2593
2799
|
|
|
2594
2800
|
if (version.equals(this.implementation.getCurrentBundle().getVersionName())) {
|
|
2595
2801
|
logger.info("Preview payload unchanged, reloading current bundle");
|
|
2596
|
-
return this.
|
|
2802
|
+
return this.reloadWithoutWaitingForAppReady();
|
|
2597
2803
|
}
|
|
2598
2804
|
|
|
2599
2805
|
final BundleInfo next = this.downloadPreviewPayloadBundle(payload);
|
|
@@ -2605,7 +2811,7 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
2605
2811
|
}
|
|
2606
2812
|
|
|
2607
2813
|
this.notifyBundleSet(next);
|
|
2608
|
-
return this.
|
|
2814
|
+
return this.reloadWithoutWaitingForAppReady();
|
|
2609
2815
|
} catch (final Exception err) {
|
|
2610
2816
|
logger.error("Could not refresh preview session: " + err.getMessage());
|
|
2611
2817
|
return false;
|
|
@@ -2619,6 +2825,7 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
2619
2825
|
logger.info("Native build changed; clearing preview session state");
|
|
2620
2826
|
this.previewSessionEnabled = false;
|
|
2621
2827
|
this.previewSessionAlertPending = false;
|
|
2828
|
+
this.isLeavingPreviewForIncomingLink = false;
|
|
2622
2829
|
this.implementation.previewSession = false;
|
|
2623
2830
|
this.shakeMenuEnabled = this.getConfig().getBoolean("shakeMenu", false);
|
|
2624
2831
|
this.shakeChannelSelectorEnabled = this.getConfig().getBoolean("allowShakeChannelSelector", false);
|
|
@@ -2657,30 +2864,33 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
2657
2864
|
return;
|
|
2658
2865
|
}
|
|
2659
2866
|
this.previewSessionAlertPending = false;
|
|
2867
|
+
this.editor.putBoolean(PREVIEW_SESSION_ALERT_PENDING_PREF_KEY, false);
|
|
2868
|
+
this.editor.apply();
|
|
2660
2869
|
|
|
2661
|
-
new Handler(Looper.getMainLooper()).postDelayed(
|
|
2662
|
-
|
|
2663
|
-
|
|
2664
|
-
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
if (getActivity() == null || getActivity().isFinishing()) {
|
|
2668
|
-
this.previewSessionAlertPending = true;
|
|
2669
|
-
return;
|
|
2670
|
-
}
|
|
2671
|
-
|
|
2672
|
-
new AlertDialog.Builder(getActivity())
|
|
2673
|
-
.setTitle("Preview started")
|
|
2674
|
-
.setMessage("Shake your device anytime to reload or leave the test app.")
|
|
2675
|
-
.setPositiveButton("Got it", (dialog, which) -> dialog.dismiss())
|
|
2676
|
-
.show();
|
|
2677
|
-
} catch (final Exception e) {
|
|
2870
|
+
new Handler(Looper.getMainLooper()).postDelayed(() -> {
|
|
2871
|
+
try {
|
|
2872
|
+
if (!Boolean.TRUE.equals(this.previewSessionEnabled)) {
|
|
2873
|
+
return;
|
|
2874
|
+
}
|
|
2875
|
+
if (getActivity() == null || getActivity().isFinishing()) {
|
|
2678
2876
|
this.previewSessionAlertPending = true;
|
|
2679
|
-
|
|
2877
|
+
this.editor.putBoolean(PREVIEW_SESSION_ALERT_PENDING_PREF_KEY, true);
|
|
2878
|
+
this.editor.apply();
|
|
2879
|
+
return;
|
|
2680
2880
|
}
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
|
|
2881
|
+
|
|
2882
|
+
new AlertDialog.Builder(getActivity())
|
|
2883
|
+
.setTitle("Preview started")
|
|
2884
|
+
.setMessage("Shake your device anytime to reload or leave the test app.")
|
|
2885
|
+
.setPositiveButton("Got it", (dialog, which) -> dialog.dismiss())
|
|
2886
|
+
.show();
|
|
2887
|
+
} catch (final Exception e) {
|
|
2888
|
+
this.previewSessionAlertPending = true;
|
|
2889
|
+
this.editor.putBoolean(PREVIEW_SESSION_ALERT_PENDING_PREF_KEY, true);
|
|
2890
|
+
this.editor.apply();
|
|
2891
|
+
logger.warn("Could not show preview session notice: " + e.getMessage());
|
|
2892
|
+
}
|
|
2893
|
+
}, 600);
|
|
2684
2894
|
}
|
|
2685
2895
|
|
|
2686
2896
|
@PluginMethod
|
|
@@ -2886,6 +3096,9 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
2886
3096
|
logger.error("Error no url or wrong format");
|
|
2887
3097
|
return "unavailable";
|
|
2888
3098
|
}
|
|
3099
|
+
if (this.shouldBlockAutoUpdateForPreviewSession()) {
|
|
3100
|
+
return "preview_session";
|
|
3101
|
+
}
|
|
2889
3102
|
if (this.isDownloadStuckOrTimedOut()) {
|
|
2890
3103
|
logger.info("Download already in progress, skipping duplicate download request");
|
|
2891
3104
|
return "already_running";
|
|
@@ -3054,7 +3267,13 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
3054
3267
|
@Override
|
|
3055
3268
|
public void run() {
|
|
3056
3269
|
try {
|
|
3270
|
+
if (CapacitorUpdaterPlugin.this.shouldBlockAutoUpdateForPreviewSession()) {
|
|
3271
|
+
return;
|
|
3272
|
+
}
|
|
3057
3273
|
CapacitorUpdaterPlugin.this.implementation.getLatest(CapacitorUpdaterPlugin.this.updateUrl, null, (res) -> {
|
|
3274
|
+
if (CapacitorUpdaterPlugin.this.shouldBlockAutoUpdateForPreviewSession()) {
|
|
3275
|
+
return;
|
|
3276
|
+
}
|
|
3058
3277
|
JSObject jsRes = InternalUtils.mapToJSObject(res);
|
|
3059
3278
|
if (jsRes.has("error") || jsRes.has("kind")) {
|
|
3060
3279
|
final BundleInfo current = CapacitorUpdaterPlugin.this.implementation.getCurrentBundle();
|
|
@@ -3117,6 +3336,7 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
3117
3336
|
logger.info("semaphoreReady countDown");
|
|
3118
3337
|
this.semaphoreDown();
|
|
3119
3338
|
logger.info("semaphoreReady countDown done");
|
|
3339
|
+
this.clearIncomingPreviewTransition();
|
|
3120
3340
|
final JSObject ret = new JSObject();
|
|
3121
3341
|
ret.put("bundle", InternalUtils.mapToJSObject(bundle.toJSONMap()));
|
|
3122
3342
|
call.resolve(ret);
|
|
@@ -3164,6 +3384,9 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
3164
3384
|
}
|
|
3165
3385
|
|
|
3166
3386
|
private Boolean _isAutoUpdateEnabled() {
|
|
3387
|
+
if (this.isPreviewSessionStateActive()) {
|
|
3388
|
+
return false;
|
|
3389
|
+
}
|
|
3167
3390
|
final CapConfig config = CapConfig.loadDefault(this.getActivity());
|
|
3168
3391
|
String serverUrl = config.getServerUrl();
|
|
3169
3392
|
if (serverUrl != null && !serverUrl.isEmpty()) {
|
|
@@ -3362,6 +3585,11 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
3362
3585
|
logger.info("endBackGroundTaskWithNotif " + msg);
|
|
3363
3586
|
}
|
|
3364
3587
|
|
|
3588
|
+
private void clearBackgroundDownloadState() {
|
|
3589
|
+
this.backgroundDownloadTask = null;
|
|
3590
|
+
this.downloadStartTimeMs = 0;
|
|
3591
|
+
}
|
|
3592
|
+
|
|
3365
3593
|
private boolean isDownloadStuckOrTimedOut() {
|
|
3366
3594
|
if (this.backgroundDownloadTask == null || !this.backgroundDownloadTask.isAlive()) {
|
|
3367
3595
|
return false;
|
|
@@ -3388,6 +3616,9 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
3388
3616
|
}
|
|
3389
3617
|
|
|
3390
3618
|
private Thread backgroundDownload() {
|
|
3619
|
+
if (this.shouldBlockAutoUpdateForPreviewSession()) {
|
|
3620
|
+
return null;
|
|
3621
|
+
}
|
|
3391
3622
|
final boolean plannedDirectUpdate = this.shouldUseDirectUpdate();
|
|
3392
3623
|
final boolean initialDirectUpdateAllowed = this.isDirectUpdateCurrentlyAllowed(plannedDirectUpdate);
|
|
3393
3624
|
final String messageUpdate = initialDirectUpdateAllowed
|
|
@@ -3398,9 +3629,17 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
3398
3629
|
Thread newTask = startNewThread(() -> {
|
|
3399
3630
|
// Wait for cleanup to complete before starting download
|
|
3400
3631
|
waitForCleanupIfNeeded();
|
|
3632
|
+
if (CapacitorUpdaterPlugin.this.shouldBlockAutoUpdateForPreviewSession()) {
|
|
3633
|
+
CapacitorUpdaterPlugin.this.clearBackgroundDownloadState();
|
|
3634
|
+
return;
|
|
3635
|
+
}
|
|
3401
3636
|
logger.info("Check for update via: " + CapacitorUpdaterPlugin.this.updateUrl);
|
|
3402
3637
|
try {
|
|
3403
3638
|
CapacitorUpdaterPlugin.this.implementation.getLatest(CapacitorUpdaterPlugin.this.updateUrl, null, (res) -> {
|
|
3639
|
+
if (CapacitorUpdaterPlugin.this.shouldBlockAutoUpdateForPreviewSession()) {
|
|
3640
|
+
CapacitorUpdaterPlugin.this.clearBackgroundDownloadState();
|
|
3641
|
+
return;
|
|
3642
|
+
}
|
|
3404
3643
|
JSObject jsRes = InternalUtils.mapToJSObject(res);
|
|
3405
3644
|
final BundleInfo current = CapacitorUpdaterPlugin.this.implementation.getCurrentBundle();
|
|
3406
3645
|
|
|
@@ -3625,6 +3864,10 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
3625
3864
|
: initialDirectUpdateAllowed;
|
|
3626
3865
|
startNewThread(() -> {
|
|
3627
3866
|
try {
|
|
3867
|
+
if (CapacitorUpdaterPlugin.this.shouldBlockAutoUpdateForPreviewSession()) {
|
|
3868
|
+
CapacitorUpdaterPlugin.this.clearBackgroundDownloadState();
|
|
3869
|
+
return;
|
|
3870
|
+
}
|
|
3628
3871
|
logger.info(
|
|
3629
3872
|
"New bundle: " +
|
|
3630
3873
|
latestVersionName +
|
|
@@ -3711,6 +3954,9 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
3711
3954
|
|
|
3712
3955
|
private void installNext() {
|
|
3713
3956
|
try {
|
|
3957
|
+
if (this.shouldBlockAutoUpdateForPreviewSession()) {
|
|
3958
|
+
return;
|
|
3959
|
+
}
|
|
3714
3960
|
String delayUpdatePreferences = prefs.getString(DelayUpdateUtils.DELAY_CONDITION_PREFERENCES, "[]");
|
|
3715
3961
|
ArrayList<DelayCondition> delayConditionList = delayUpdateUtils.parseDelayConditions(delayUpdatePreferences);
|
|
3716
3962
|
if (!delayConditionList.isEmpty()) {
|
|
@@ -3746,6 +3992,10 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
3746
3992
|
logger.info("Built-in bundle is active. We skip the check for notifyAppReady.");
|
|
3747
3993
|
return;
|
|
3748
3994
|
}
|
|
3995
|
+
if (this.isPreviewSessionStateActive()) {
|
|
3996
|
+
logger.info("Preview session is active. We skip the check for notifyAppReady.");
|
|
3997
|
+
return;
|
|
3998
|
+
}
|
|
3749
3999
|
logger.debug("Current bundle is: " + current);
|
|
3750
4000
|
|
|
3751
4001
|
if (BundleStatus.SUCCESS != current.getStatus()) {
|
|
@@ -3920,6 +4170,34 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
3920
4170
|
}
|
|
3921
4171
|
}
|
|
3922
4172
|
|
|
4173
|
+
@Override
|
|
4174
|
+
protected void handleOnNewIntent(Intent intent) {
|
|
4175
|
+
super.handleOnNewIntent(intent);
|
|
4176
|
+
if (
|
|
4177
|
+
intent == null ||
|
|
4178
|
+
!Intent.ACTION_VIEW.equals(intent.getAction()) ||
|
|
4179
|
+
intent.getData() == null ||
|
|
4180
|
+
!Boolean.TRUE.equals(this.previewSessionEnabled) ||
|
|
4181
|
+
!isPreviewDeepLink(intent.getData()) ||
|
|
4182
|
+
Boolean.TRUE.equals(this.isLeavingPreviewForIncomingLink)
|
|
4183
|
+
) {
|
|
4184
|
+
return;
|
|
4185
|
+
}
|
|
4186
|
+
|
|
4187
|
+
this.isLeavingPreviewForIncomingLink = true;
|
|
4188
|
+
if (getActivity() != null) {
|
|
4189
|
+
getActivity().setIntent(intent);
|
|
4190
|
+
}
|
|
4191
|
+
logger.info("Preview deeplink received while preview session is active; restoring fallback before routing");
|
|
4192
|
+
startNewThread(() -> {
|
|
4193
|
+
final boolean didLeave = this.leavePreviewSessionForIncomingPreviewLink();
|
|
4194
|
+
if (!didLeave) {
|
|
4195
|
+
logger.error("Could not leave preview session before routing incoming preview deeplink");
|
|
4196
|
+
this.isLeavingPreviewForIncomingLink = false;
|
|
4197
|
+
}
|
|
4198
|
+
});
|
|
4199
|
+
}
|
|
4200
|
+
|
|
3923
4201
|
@Override
|
|
3924
4202
|
public void handleOnStart() {
|
|
3925
4203
|
try {
|