@capgo/capacitor-updater 7.8.3 → 7.8.5

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.
@@ -59,7 +59,7 @@ public class CapacitorUpdaterPlugin extends Plugin {
59
59
  private static final String statsUrlDefault = "https://plugin.capgo.app/stats";
60
60
  private static final String channelUrlDefault = "https://plugin.capgo.app/channel_self";
61
61
 
62
- private final String PLUGIN_VERSION = "7.8.3";
62
+ private final String PLUGIN_VERSION = "7.8.5";
63
63
  private static final String DELAY_CONDITION_PREFERENCES = "";
64
64
 
65
65
  private SharedPreferences.Editor editor;
@@ -314,8 +314,8 @@ public class CapacitorUpdaterPlugin extends Plugin {
314
314
 
315
315
  PluginCall call = new PluginCall(
316
316
  (com.getcapacitor.MessageHandler) msgHandler,
317
- "autoHideSplashscreen",
318
- PluginCall.CALLBACK_ID_DANGLING,
317
+ "SplashScreen",
318
+ "FAKE_CALLBACK_ID_HIDE",
319
319
  "hide",
320
320
  options
321
321
  );
@@ -340,39 +340,52 @@ public class CapacitorUpdaterPlugin extends Plugin {
340
340
 
341
341
  private void showSplashscreen() {
342
342
  try {
343
- // Try to call the SplashScreen plugin directly through the bridge
343
+ // Show splashscreen immediately and synchronously when backgrounding
344
+ if (getBridge() == null) {
345
+ logger.warn("Bridge not ready for showing splashscreen with autoSplashscreen");
346
+ return;
347
+ }
348
+
349
+ // Execute immediately on current thread if it's main, otherwise post to main thread
350
+ if (android.os.Looper.myLooper() == android.os.Looper.getMainLooper()) {
351
+ showSplashscreenNow();
352
+ } else {
353
+ // Use runOnUiThread for immediate execution on main thread
354
+ if (getActivity() != null) {
355
+ getActivity().runOnUiThread(() -> showSplashscreenNow());
356
+ } else {
357
+ new android.os.Handler(android.os.Looper.getMainLooper()).post(() -> showSplashscreenNow());
358
+ }
359
+ }
360
+ } catch (Exception e) {
361
+ logger.error("Error showing splashscreen when backgrounding: " + e.getMessage());
362
+ }
363
+ }
364
+
365
+ private void showSplashscreenNow() {
366
+ try {
344
367
  PluginHandle splashScreenPlugin = getBridge().getPlugin("SplashScreen");
345
368
  if (splashScreenPlugin != null) {
346
- try {
347
- // Create a plugin call for the show method using reflection to access private msgHandler
348
- JSObject options = new JSObject();
349
- java.lang.reflect.Field msgHandlerField = getBridge().getClass().getDeclaredField("msgHandler");
350
- msgHandlerField.setAccessible(true);
351
- Object msgHandler = msgHandlerField.get(getBridge());
352
-
353
- PluginCall call = new PluginCall(
354
- (com.getcapacitor.MessageHandler) msgHandler,
355
- "autoShowSplashscreen",
356
- PluginCall.CALLBACK_ID_DANGLING,
357
- "show",
358
- options
359
- );
369
+ JSObject options = new JSObject();
370
+ java.lang.reflect.Field msgHandlerField = getBridge().getClass().getDeclaredField("msgHandler");
371
+ msgHandlerField.setAccessible(true);
372
+ Object msgHandler = msgHandlerField.get(getBridge());
373
+
374
+ PluginCall call = new PluginCall(
375
+ (com.getcapacitor.MessageHandler) msgHandler,
376
+ "SplashScreen",
377
+ "FAKE_CALLBACK_ID_SHOW",
378
+ "show",
379
+ options
380
+ );
360
381
 
361
- // Call the show method directly
362
- splashScreenPlugin.invoke("show", call);
363
- logger.info("Splashscreen shown automatically via direct plugin call");
364
- } catch (Exception e) {
365
- logger.error("Failed to call SplashScreen show method: " + e.getMessage());
366
- }
382
+ splashScreenPlugin.invoke("show", call);
383
+ logger.info("Splashscreen shown synchronously to prevent flash");
367
384
  } else {
368
- logger.warn("autoSplashscreen: SplashScreen plugin not found. Install @capacitor/splash-screen plugin.");
385
+ logger.warn("autoSplashscreen: SplashScreen plugin not found");
369
386
  }
370
387
  } catch (Exception e) {
371
- logger.error(
372
- "Error showing splashscreen with autoSplashscreen: " +
373
- e.getMessage() +
374
- ". Make sure @capacitor/splash-screen plugin is installed and configured."
375
- );
388
+ logger.error("Failed to show splashscreen synchronously: " + e.getMessage());
376
389
  }
377
390
  }
378
391
 
@@ -1519,6 +1532,7 @@ public class CapacitorUpdaterPlugin extends Plugin {
1519
1532
  CapacitorUpdaterPlugin.this.implementation.sendStats("app_moved_to_foreground", current.getVersionName());
1520
1533
  this.delayUpdateUtils.checkCancelDelay(DelayUpdateUtils.CancelDelaySource.FOREGROUND);
1521
1534
  this.delayUpdateUtils.unsetBackgroundTimestamp();
1535
+
1522
1536
  if (
1523
1537
  CapacitorUpdaterPlugin.this._isAutoUpdateEnabled() &&
1524
1538
  (this.backgroundDownloadTask == null || !this.backgroundDownloadTask.isAlive())
@@ -1533,10 +1547,8 @@ public class CapacitorUpdaterPlugin extends Plugin {
1533
1547
 
1534
1548
  public void appMovedToBackground() {
1535
1549
  final BundleInfo current = CapacitorUpdaterPlugin.this.implementation.getCurrentBundle();
1536
- CapacitorUpdaterPlugin.this.implementation.sendStats("app_moved_to_background", current.getVersionName());
1537
- logger.info("Checking for pending update");
1538
1550
 
1539
- // Show splashscreen only if autoSplashscreen is enabled AND autoUpdate is enabled AND directUpdate would be used
1551
+ // Show splashscreen FIRST, before any other background work to ensure launcher shows it
1540
1552
  if (this.autoSplashscreen) {
1541
1553
  boolean canShowSplashscreen = true;
1542
1554
 
@@ -1555,10 +1567,15 @@ public class CapacitorUpdaterPlugin extends Plugin {
1555
1567
  }
1556
1568
 
1557
1569
  if (canShowSplashscreen) {
1570
+ logger.info("Showing splashscreen for launcher/task switcher");
1558
1571
  this.showSplashscreen();
1559
1572
  }
1560
1573
  }
1561
1574
 
1575
+ // Do other background work after splashscreen is shown
1576
+ CapacitorUpdaterPlugin.this.implementation.sendStats("app_moved_to_background", current.getVersionName());
1577
+ logger.info("Checking for pending update");
1578
+
1562
1579
  try {
1563
1580
  // We need to set "backgrounded time"
1564
1581
  this.delayUpdateUtils.setBackgroundTimestamp(System.currentTimeMillis());
@@ -7,6 +7,42 @@
7
7
  import Foundation
8
8
  import Capacitor
9
9
  import Version
10
+ import WebKit
11
+
12
+ // Helper class to detect when WebView loading completes
13
+ class WebViewLoadDelegate: NSObject, WKNavigationDelegate {
14
+ private let completion: (Bool) -> Void
15
+ private var hasCompleted = false
16
+
17
+ init(completion: @escaping (Bool) -> Void) {
18
+ self.completion = completion
19
+ super.init()
20
+ }
21
+
22
+ func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
23
+ if !hasCompleted {
24
+ hasCompleted = true
25
+ webView.navigationDelegate = nil // Clean up
26
+ completion(true)
27
+ }
28
+ }
29
+
30
+ func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
31
+ if !hasCompleted {
32
+ hasCompleted = true
33
+ webView.navigationDelegate = nil // Clean up
34
+ completion(false)
35
+ }
36
+ }
37
+
38
+ func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {
39
+ if !hasCompleted {
40
+ hasCompleted = true
41
+ webView.navigationDelegate = nil // Clean up
42
+ completion(false)
43
+ }
44
+ }
45
+ }
10
46
 
11
47
  /**
12
48
  * Please read the Capacitor iOS Plugin Development Guide
@@ -50,7 +86,7 @@ public class CapacitorUpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
50
86
  CAPPluginMethod(name: "isShakeMenuEnabled", returnType: CAPPluginReturnPromise)
51
87
  ]
52
88
  public var implementation = CapgoUpdater()
53
- private let PLUGIN_VERSION: String = "7.8.3"
89
+ private let PLUGIN_VERSION: String = "7.8.5"
54
90
  static let updateUrlDefault = "https://plugin.capgo.app/updates"
55
91
  static let statsUrlDefault = "https://plugin.capgo.app/stats"
56
92
  static let channelUrlDefault = "https://plugin.capgo.app/channel_self"
@@ -409,27 +445,62 @@ public class CapacitorUpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
409
445
  logger.error("Cannot get capBridge")
410
446
  return false
411
447
  }
448
+
449
+ // Use semaphore to wait for WebView load completion
450
+ let loadSemaphore = DispatchSemaphore(value: 0)
451
+ var loadSuccess = false
452
+
453
+ // Set up navigation delegate to detect when loading completes
454
+ let navigationDelegate = WebViewLoadDelegate { [weak self] success in
455
+ loadSuccess = success
456
+ if success {
457
+ self?.checkAppReady()
458
+ self?.notifyListeners("appReloaded", data: [:])
459
+ }
460
+ loadSemaphore.signal()
461
+ }
462
+
412
463
  if keepUrlPathAfterReload {
413
464
  DispatchQueue.main.async {
414
465
  guard let url = vc.webView?.url else {
415
466
  self.logger.error("vc.webView?.url is null?")
467
+ loadSuccess = false
468
+ loadSemaphore.signal()
416
469
  return
417
470
  }
418
471
  capBridge.setServerBasePath(dest.path)
419
472
  var urlComponents = URLComponents(url: capBridge.config.serverURL, resolvingAgainstBaseURL: false)!
420
473
  urlComponents.path = url.path
421
474
  if let finalUrl = urlComponents.url {
475
+ vc.webView?.navigationDelegate = navigationDelegate
422
476
  _ = vc.webView?.load(URLRequest(url: finalUrl))
477
+ } else {
478
+ loadSuccess = false
479
+ loadSemaphore.signal()
423
480
  }
424
481
  }
425
482
  } else {
426
483
  vc.setServerBasePath(path: dest.path)
427
-
484
+ // For setServerBasePath, we need to wait for the next page load
485
+ vc.webView?.navigationDelegate = navigationDelegate
486
+ // Trigger a reload to ensure the new path is loaded
487
+ DispatchQueue.main.async {
488
+ vc.webView?.reload()
489
+ }
428
490
  }
429
-
430
- self.checkAppReady()
431
- self.notifyListeners("appReloaded", data: [:])
432
- return true
491
+
492
+ // Wait for load completion with timeout
493
+ let result = loadSemaphore.wait(timeout: .now() + 10) // 10 second timeout
494
+
495
+ if result == .timedOut {
496
+ logger.error("Reload timed out after 10 seconds")
497
+ DispatchQueue.main.async {
498
+ vc.webView?.navigationDelegate = nil // Clean up
499
+ }
500
+ return false
501
+ }
502
+
503
+ return loadSuccess
433
504
  }
434
505
  return false
435
506
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capgo/capacitor-updater",
3
- "version": "7.8.3",
3
+ "version": "7.8.5",
4
4
  "license": "MPL-2.0",
5
5
  "description": "Live update for capacitor apps",
6
6
  "main": "dist/plugin.cjs.js",