@capgo/capacitor-updater 8.45.8 → 8.45.10
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/build.gradle
CHANGED
|
@@ -54,7 +54,7 @@ dependencies {
|
|
|
54
54
|
implementation "androidx.work:work-runtime:$work_version"
|
|
55
55
|
implementation "androidx.lifecycle:lifecycle-process:$lifecycle_version"
|
|
56
56
|
implementation "com.google.android.gms:play-services-tasks:18.4.1"
|
|
57
|
-
implementation "com.google.guava:guava:33.
|
|
57
|
+
implementation "com.google.guava:guava:33.6.0-android"
|
|
58
58
|
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
|
59
59
|
implementation project(':capacitor-android')
|
|
60
60
|
implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion"
|
|
@@ -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.10";
|
|
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,68 +1492,64 @@ 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
|
|
1459
1507
|
public void reload(final PluginCall call) {
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
this.implementation.prepareResetStateForTransition();
|
|
1471
|
-
didApplyPendingBundle = true;
|
|
1472
|
-
} else {
|
|
1473
|
-
didApplyPendingBundle = this.implementation.stagePendingReload(next);
|
|
1474
|
-
}
|
|
1475
|
-
if (didApplyPendingBundle && this._reload()) {
|
|
1508
|
+
startNewThread(() -> {
|
|
1509
|
+
try {
|
|
1510
|
+
final BundleInfo current = this.implementation.getCurrentBundle();
|
|
1511
|
+
final BundleInfo next = this.implementation.getNextBundle();
|
|
1512
|
+
|
|
1513
|
+
if (next != null && !next.isErrorStatus() && !next.getId().equals(current.getId())) {
|
|
1514
|
+
final CapgoUpdater.ResetState previousState = this.implementation.captureResetState();
|
|
1515
|
+
final String previousBundleName = this.implementation.getCurrentBundle().getVersionName();
|
|
1516
|
+
logger.info("Applying pending bundle before reload: " + next.getVersionName());
|
|
1517
|
+
final boolean didApplyPendingBundle;
|
|
1476
1518
|
if (next.isBuiltin()) {
|
|
1477
|
-
this.implementation.
|
|
1519
|
+
this.implementation.prepareResetStateForTransition();
|
|
1520
|
+
didApplyPendingBundle = true;
|
|
1478
1521
|
} else {
|
|
1479
|
-
this.implementation.
|
|
1522
|
+
didApplyPendingBundle = this.implementation.stagePendingReload(next);
|
|
1480
1523
|
}
|
|
1481
|
-
this.
|
|
1482
|
-
|
|
1483
|
-
|
|
1524
|
+
if (didApplyPendingBundle && this._reload()) {
|
|
1525
|
+
if (next.isBuiltin()) {
|
|
1526
|
+
this.implementation.finalizeResetTransition(previousBundleName, false);
|
|
1527
|
+
} else {
|
|
1528
|
+
this.implementation.finalizePendingReload(next, previousBundleName);
|
|
1529
|
+
}
|
|
1530
|
+
this.notifyBundleSet(next);
|
|
1531
|
+
this.implementation.setNextBundle(null);
|
|
1532
|
+
call.resolve();
|
|
1533
|
+
return;
|
|
1534
|
+
}
|
|
1535
|
+
this.implementation.restoreResetState(previousState);
|
|
1536
|
+
this.restoreLiveBundleStateAfterFailedReload();
|
|
1537
|
+
logger.error("Reload failed after applying pending bundle: " + next.getVersionName());
|
|
1538
|
+
call.reject("Reload failed after applying pending bundle: " + next.getVersionName());
|
|
1484
1539
|
return;
|
|
1485
1540
|
}
|
|
1486
|
-
this.implementation.restoreResetState(previousState);
|
|
1487
|
-
this.restoreLiveBundleStateAfterFailedReload();
|
|
1488
|
-
logger.error("Reload failed after applying pending bundle: " + next.getVersionName());
|
|
1489
|
-
call.reject("Reload failed after applying pending bundle: " + next.getVersionName());
|
|
1490
|
-
return;
|
|
1491
|
-
}
|
|
1492
1541
|
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1542
|
+
if (this._reload()) {
|
|
1543
|
+
call.resolve();
|
|
1544
|
+
} else {
|
|
1545
|
+
logger.error("Reload failed");
|
|
1546
|
+
call.reject("Reload failed");
|
|
1547
|
+
}
|
|
1548
|
+
} catch (final Exception e) {
|
|
1549
|
+
logger.error("Could not reload " + e.getMessage());
|
|
1550
|
+
call.reject("Could not reload", e);
|
|
1498
1551
|
}
|
|
1499
|
-
}
|
|
1500
|
-
logger.error("Could not reload " + e.getMessage());
|
|
1501
|
-
call.reject("Could not reload", e);
|
|
1502
|
-
}
|
|
1552
|
+
});
|
|
1503
1553
|
}
|
|
1504
1554
|
|
|
1505
1555
|
@PluginMethod
|
|
@@ -1929,11 +1979,15 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
1929
1979
|
}
|
|
1930
1980
|
|
|
1931
1981
|
private void checkAppReady() {
|
|
1982
|
+
this.checkAppReady(this.resolveAppReadyCheckTimeoutMs());
|
|
1983
|
+
}
|
|
1984
|
+
|
|
1985
|
+
private void checkAppReady(final long waitTimeMs) {
|
|
1932
1986
|
try {
|
|
1933
1987
|
if (this.appReadyCheck != null) {
|
|
1934
1988
|
this.appReadyCheck.interrupt();
|
|
1935
1989
|
}
|
|
1936
|
-
this.appReadyCheck = startNewThread(new DeferredNotifyAppReadyCheck());
|
|
1990
|
+
this.appReadyCheck = startNewThread(new DeferredNotifyAppReadyCheck(waitTimeMs));
|
|
1937
1991
|
} catch (final Exception e) {
|
|
1938
1992
|
logger.error("Failed to start " + DeferredNotifyAppReadyCheck.class.getName() + " " + e.getMessage());
|
|
1939
1993
|
}
|
|
@@ -2325,16 +2379,18 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
2325
2379
|
if (next != null && !next.isErrorStatus() && !next.getId().equals(current.getId())) {
|
|
2326
2380
|
// There is a next bundle waiting for activation
|
|
2327
2381
|
logger.debug("Next bundle is: " + next.getVersionName());
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2382
|
+
startNewThread(() -> {
|
|
2383
|
+
if (this.implementation.set(next) && this._reload()) {
|
|
2384
|
+
logger.info("Updated to bundle: " + next.getVersionName());
|
|
2385
|
+
this.notifyBundleSet(next);
|
|
2386
|
+
this.implementation.setNextBundle(null);
|
|
2387
|
+
} else {
|
|
2388
|
+
logger.error("Update to bundle: " + next.getVersionName() + " Failed!");
|
|
2389
|
+
}
|
|
2390
|
+
});
|
|
2335
2391
|
}
|
|
2336
2392
|
} catch (final Exception e) {
|
|
2337
|
-
logger.error("Error during
|
|
2393
|
+
logger.error("Error during installNext " + e);
|
|
2338
2394
|
}
|
|
2339
2395
|
}
|
|
2340
2396
|
|
|
@@ -2376,11 +2432,17 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
2376
2432
|
|
|
2377
2433
|
private class DeferredNotifyAppReadyCheck implements Runnable {
|
|
2378
2434
|
|
|
2435
|
+
private final long waitTimeMs;
|
|
2436
|
+
|
|
2437
|
+
DeferredNotifyAppReadyCheck(final long waitTimeMs) {
|
|
2438
|
+
this.waitTimeMs = waitTimeMs;
|
|
2439
|
+
}
|
|
2440
|
+
|
|
2379
2441
|
@Override
|
|
2380
2442
|
public void run() {
|
|
2381
2443
|
try {
|
|
2382
|
-
logger.info("Wait for " +
|
|
2383
|
-
Thread.sleep(
|
|
2444
|
+
logger.info("Wait for " + this.waitTimeMs + "ms, then check for notifyAppReady");
|
|
2445
|
+
Thread.sleep(this.waitTimeMs);
|
|
2384
2446
|
CapacitorUpdaterPlugin.this.checkRevert();
|
|
2385
2447
|
CapacitorUpdaterPlugin.this.appReadyCheck = null;
|
|
2386
2448
|
} 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.10"
|
|
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.10",
|
|
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",
|