@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.
|
|
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
|
-
"
|
|
318
|
-
|
|
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
|
-
//
|
|
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
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
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
|
-
|
|
362
|
-
|
|
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
|
|
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
|
|
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.
|
|
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
|
-
|
|
431
|
-
|
|
432
|
-
|
|
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
|
}
|