@capgo/capacitor-updater 8.45.8 → 8.45.9
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.
|
@@ -88,8 +88,9 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
88
88
|
private static final String SPLASH_SCREEN_PLUGIN_ID = "SplashScreen";
|
|
89
89
|
private static final int SPLASH_SCREEN_RETRY_DELAY_MS = 100;
|
|
90
90
|
private static final int SPLASH_SCREEN_MAX_RETRIES = 20;
|
|
91
|
+
private static final long PENDING_BUNDLE_APP_READY_MIN_TIMEOUT_MS = 30000L;
|
|
91
92
|
|
|
92
|
-
private final String pluginVersion = "8.45.
|
|
93
|
+
private final String pluginVersion = "8.45.9";
|
|
93
94
|
private static final String DELAY_CONDITION_PREFERENCES = "";
|
|
94
95
|
|
|
95
96
|
private SharedPreferences.Editor editor;
|
|
@@ -134,8 +135,12 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
134
135
|
private volatile long downloadStartTimeMs = 0;
|
|
135
136
|
private static final long DOWNLOAD_TIMEOUT_MS = 3600000; // 1 hour timeout
|
|
136
137
|
|
|
137
|
-
|
|
138
|
-
|
|
138
|
+
private final Phaser semaphoreReady = new Phaser(0) {
|
|
139
|
+
@Override
|
|
140
|
+
protected boolean onAdvance(final int phase, final int registeredParties) {
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
143
|
+
};
|
|
139
144
|
|
|
140
145
|
// Lock to ensure cleanup completes before downloads start
|
|
141
146
|
private final Object cleanupLock = new Object();
|
|
@@ -284,13 +289,7 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
284
289
|
|
|
285
290
|
@Override
|
|
286
291
|
public void directUpdateFinish(final BundleInfo latest) {
|
|
287
|
-
|
|
288
|
-
activity.runOnUiThread(() -> {
|
|
289
|
-
CapacitorUpdaterPlugin.this.directUpdateFinish(latest);
|
|
290
|
-
});
|
|
291
|
-
} else {
|
|
292
|
-
logger.warn("directUpdateFinish: Activity is null, skipping notification");
|
|
293
|
-
}
|
|
292
|
+
CapacitorUpdaterPlugin.this.scheduleDirectUpdateFinish(latest);
|
|
294
293
|
}
|
|
295
294
|
|
|
296
295
|
@Override
|
|
@@ -521,30 +520,69 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
521
520
|
}
|
|
522
521
|
}
|
|
523
522
|
|
|
524
|
-
private
|
|
523
|
+
private boolean semaphoreWait(final int phase, Number waitTime) {
|
|
525
524
|
try {
|
|
526
|
-
semaphoreReady.awaitAdvanceInterruptibly(
|
|
525
|
+
semaphoreReady.awaitAdvanceInterruptibly(phase, waitTime.longValue(), TimeUnit.MILLISECONDS);
|
|
527
526
|
logger.info("semaphoreReady count " + semaphoreReady.getPhase());
|
|
527
|
+
return true;
|
|
528
528
|
} catch (InterruptedException e) {
|
|
529
529
|
logger.info("semaphoreWait InterruptedException");
|
|
530
|
+
cleanupTimedOutSemaphoreWait(phase);
|
|
530
531
|
Thread.currentThread().interrupt(); // Restore interrupted status
|
|
532
|
+
return false;
|
|
531
533
|
} catch (TimeoutException e) {
|
|
532
534
|
logger.error("Semaphore timeout: " + e.getMessage());
|
|
533
|
-
|
|
535
|
+
cleanupTimedOutSemaphoreWait(phase);
|
|
536
|
+
return false;
|
|
534
537
|
}
|
|
535
538
|
}
|
|
536
539
|
|
|
537
|
-
private
|
|
540
|
+
private int semaphoreUp() {
|
|
538
541
|
logger.info("semaphoreUp");
|
|
539
|
-
semaphoreReady.register();
|
|
542
|
+
return semaphoreReady.register();
|
|
540
543
|
}
|
|
541
544
|
|
|
542
545
|
private void semaphoreDown() {
|
|
546
|
+
if (semaphoreReady.getRegisteredParties() == 0) {
|
|
547
|
+
logger.info("semaphoreDown skipped, no pending app ready wait");
|
|
548
|
+
return;
|
|
549
|
+
}
|
|
543
550
|
logger.info("semaphoreDown");
|
|
544
551
|
logger.info("semaphoreDown count " + semaphoreReady.getPhase());
|
|
545
552
|
semaphoreReady.arriveAndDeregister();
|
|
546
553
|
}
|
|
547
554
|
|
|
555
|
+
private void cleanupTimedOutSemaphoreWait(final int phase) {
|
|
556
|
+
if (semaphoreReady.getPhase() != phase || semaphoreReady.getRegisteredParties() == 0) {
|
|
557
|
+
return;
|
|
558
|
+
}
|
|
559
|
+
logger.info("Cleaning up stale app ready wait for phase " + phase);
|
|
560
|
+
semaphoreReady.arriveAndDeregister();
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
protected long getMinimumPendingBundleAppReadyTimeoutMs() {
|
|
564
|
+
return PENDING_BUNDLE_APP_READY_MIN_TIMEOUT_MS;
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
private long resolveAppReadyCheckTimeoutMs() {
|
|
568
|
+
long configuredTimeoutMs = this.appReadyTimeout.longValue();
|
|
569
|
+
try {
|
|
570
|
+
if (this.implementation == null) {
|
|
571
|
+
return configuredTimeoutMs;
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
final BundleInfo current = this.implementation.getCurrentBundle();
|
|
575
|
+
if (current == null || BundleStatus.SUCCESS == current.getStatus()) {
|
|
576
|
+
return configuredTimeoutMs;
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
return Math.max(configuredTimeoutMs, this.getMinimumPendingBundleAppReadyTimeoutMs());
|
|
580
|
+
} catch (final Exception e) {
|
|
581
|
+
logger.warn("Falling back to configured appReadyTimeout: " + e.getMessage());
|
|
582
|
+
return configuredTimeoutMs;
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
|
|
548
586
|
private void sendReadyToJs(final BundleInfo current, final String msg) {
|
|
549
587
|
sendReadyToJs(current, msg, false);
|
|
550
588
|
}
|
|
@@ -864,6 +902,22 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
864
902
|
this.endBackGroundTaskWithNotif("test", current.getVersionName(), current, false, plannedDirectUpdate);
|
|
865
903
|
}
|
|
866
904
|
|
|
905
|
+
void scheduleDirectUpdateFinish(final BundleInfo latest) {
|
|
906
|
+
startNewThread(() -> {
|
|
907
|
+
try {
|
|
908
|
+
Activity currentActivity = this.getActivity();
|
|
909
|
+
if (currentActivity != null) {
|
|
910
|
+
this.implementation.activity = currentActivity;
|
|
911
|
+
} else {
|
|
912
|
+
logger.warn("directUpdateFinish: Activity is null, proceeding without refreshing the activity reference");
|
|
913
|
+
}
|
|
914
|
+
this.directUpdateFinish(latest);
|
|
915
|
+
} catch (final Exception e) {
|
|
916
|
+
logger.error("directUpdateFinish failed: " + e.getMessage());
|
|
917
|
+
}
|
|
918
|
+
});
|
|
919
|
+
}
|
|
920
|
+
|
|
867
921
|
private void directUpdateFinish(final BundleInfo latest) {
|
|
868
922
|
if ("onLaunch".equals(this.directUpdateMode)) {
|
|
869
923
|
this.onLaunchDirectUpdateUsed = true;
|
|
@@ -1438,21 +1492,15 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
1438
1492
|
}
|
|
1439
1493
|
|
|
1440
1494
|
protected boolean _reload() {
|
|
1441
|
-
this.semaphoreUp();
|
|
1495
|
+
final int phase = this.semaphoreUp();
|
|
1442
1496
|
this.applyCurrentBundleToBridge();
|
|
1443
1497
|
|
|
1444
|
-
this.
|
|
1498
|
+
final long waitTimeMs = this.resolveAppReadyCheckTimeoutMs();
|
|
1499
|
+
this.checkAppReady(waitTimeMs);
|
|
1445
1500
|
this.notifyListeners("appReloaded", new JSObject());
|
|
1446
1501
|
|
|
1447
1502
|
// Wait for the reload to complete (until notifyAppReady is called)
|
|
1448
|
-
|
|
1449
|
-
this.semaphoreWait(this.appReadyTimeout);
|
|
1450
|
-
} catch (Exception e) {
|
|
1451
|
-
logger.error("Error waiting for app ready: " + e.getMessage());
|
|
1452
|
-
return false;
|
|
1453
|
-
}
|
|
1454
|
-
|
|
1455
|
-
return true;
|
|
1503
|
+
return this.semaphoreWait(phase, waitTimeMs);
|
|
1456
1504
|
}
|
|
1457
1505
|
|
|
1458
1506
|
@PluginMethod
|
|
@@ -1929,11 +1977,15 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
1929
1977
|
}
|
|
1930
1978
|
|
|
1931
1979
|
private void checkAppReady() {
|
|
1980
|
+
this.checkAppReady(this.resolveAppReadyCheckTimeoutMs());
|
|
1981
|
+
}
|
|
1982
|
+
|
|
1983
|
+
private void checkAppReady(final long waitTimeMs) {
|
|
1932
1984
|
try {
|
|
1933
1985
|
if (this.appReadyCheck != null) {
|
|
1934
1986
|
this.appReadyCheck.interrupt();
|
|
1935
1987
|
}
|
|
1936
|
-
this.appReadyCheck = startNewThread(new DeferredNotifyAppReadyCheck());
|
|
1988
|
+
this.appReadyCheck = startNewThread(new DeferredNotifyAppReadyCheck(waitTimeMs));
|
|
1937
1989
|
} catch (final Exception e) {
|
|
1938
1990
|
logger.error("Failed to start " + DeferredNotifyAppReadyCheck.class.getName() + " " + e.getMessage());
|
|
1939
1991
|
}
|
|
@@ -2325,16 +2377,18 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
2325
2377
|
if (next != null && !next.isErrorStatus() && !next.getId().equals(current.getId())) {
|
|
2326
2378
|
// There is a next bundle waiting for activation
|
|
2327
2379
|
logger.debug("Next bundle is: " + next.getVersionName());
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2380
|
+
startNewThread(() -> {
|
|
2381
|
+
if (this.implementation.set(next) && this._reload()) {
|
|
2382
|
+
logger.info("Updated to bundle: " + next.getVersionName());
|
|
2383
|
+
this.notifyBundleSet(next);
|
|
2384
|
+
this.implementation.setNextBundle(null);
|
|
2385
|
+
} else {
|
|
2386
|
+
logger.error("Update to bundle: " + next.getVersionName() + " Failed!");
|
|
2387
|
+
}
|
|
2388
|
+
});
|
|
2335
2389
|
}
|
|
2336
2390
|
} catch (final Exception e) {
|
|
2337
|
-
logger.error("Error during
|
|
2391
|
+
logger.error("Error during installNext " + e);
|
|
2338
2392
|
}
|
|
2339
2393
|
}
|
|
2340
2394
|
|
|
@@ -2376,11 +2430,17 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
2376
2430
|
|
|
2377
2431
|
private class DeferredNotifyAppReadyCheck implements Runnable {
|
|
2378
2432
|
|
|
2433
|
+
private final long waitTimeMs;
|
|
2434
|
+
|
|
2435
|
+
DeferredNotifyAppReadyCheck(final long waitTimeMs) {
|
|
2436
|
+
this.waitTimeMs = waitTimeMs;
|
|
2437
|
+
}
|
|
2438
|
+
|
|
2379
2439
|
@Override
|
|
2380
2440
|
public void run() {
|
|
2381
2441
|
try {
|
|
2382
|
-
logger.info("Wait for " +
|
|
2383
|
-
Thread.sleep(
|
|
2442
|
+
logger.info("Wait for " + this.waitTimeMs + "ms, then check for notifyAppReady");
|
|
2443
|
+
Thread.sleep(this.waitTimeMs);
|
|
2384
2444
|
CapacitorUpdaterPlugin.this.checkRevert();
|
|
2385
2445
|
CapacitorUpdaterPlugin.this.appReadyCheck = null;
|
|
2386
2446
|
} catch (final InterruptedException e) {
|
|
@@ -72,7 +72,7 @@ public class CapacitorUpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
72
72
|
CAPPluginMethod(name: "completeFlexibleUpdate", returnType: CAPPluginReturnPromise)
|
|
73
73
|
]
|
|
74
74
|
public var implementation = CapgoUpdater()
|
|
75
|
-
private let pluginVersion: String = "8.45.
|
|
75
|
+
private let pluginVersion: String = "8.45.9"
|
|
76
76
|
static let updateUrlDefault = "https://plugin.capgo.app/updates"
|
|
77
77
|
static let statsUrlDefault = "https://plugin.capgo.app/stats"
|
|
78
78
|
static let channelUrlDefault = "https://plugin.capgo.app/channel_self"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@capgo/capacitor-updater",
|
|
3
|
-
"version": "8.45.
|
|
3
|
+
"version": "8.45.9",
|
|
4
4
|
"license": "MPL-2.0",
|
|
5
5
|
"description": "Live update for capacitor apps",
|
|
6
6
|
"main": "dist/plugin.cjs.js",
|
|
@@ -48,6 +48,7 @@
|
|
|
48
48
|
"test": "bun run test:ios && bun run test:android",
|
|
49
49
|
"test:ios": "./scripts/test-ios.sh",
|
|
50
50
|
"test:android": "cd android && ./gradlew test && cd ..",
|
|
51
|
+
"test:maestro": "./scripts/maestro/run-android-live-update.sh",
|
|
51
52
|
"test:maestro:android": "./scripts/test-maestro-android.sh",
|
|
52
53
|
"test:maestro:ios": "./scripts/test-maestro-ios.sh",
|
|
53
54
|
"lint": "bun run eslint && bun run prettier -- --check && bun run swiftlint -- lint",
|