@capgo/capacitor-updater 8.47.6 → 8.47.7
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/README.md +13 -20
- package/android/src/main/java/ee/forgr/capacitor_updater/CapacitorUpdaterPlugin.java +175 -53
- package/android/src/main/java/ee/forgr/capacitor_updater/CapgoUpdater.java +48 -46
- package/android/src/main/java/ee/forgr/capacitor_updater/ShakeMenu.java +95 -39
- package/dist/docs.json +5 -5
- package/dist/esm/definitions.d.ts +16 -24
- package/dist/esm/definitions.js.map +1 -1
- package/ios/Sources/CapacitorUpdaterPlugin/CapacitorUpdaterPlugin.swift +182 -36
- package/ios/Sources/CapacitorUpdaterPlugin/CapgoUpdater.swift +1 -1
- package/ios/Sources/CapacitorUpdaterPlugin/InternalUtils.swift +1 -1
- package/ios/Sources/CapacitorUpdaterPlugin/ShakeMenu.swift +25 -8
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -323,8 +323,8 @@ CapacitorUpdater can be configured with these options:
|
|
|
323
323
|
| **`keepUrlPathAfterReload`** | <code>boolean</code> | Configure the plugin to keep the URL path after a reload. WARNING: When a reload is triggered, 'window.history' will be cleared. | <code>false</code> | 6.8.0 |
|
|
324
324
|
| **`disableJSLogging`** | <code>boolean</code> | Disable the JavaScript logging of the plugin. if true, the plugin will not log to the JavaScript console. only the native log will be done | <code>false</code> | 7.3.0 |
|
|
325
325
|
| **`osLogging`** | <code>boolean</code> | Enable OS-level logging. When enabled, logs are written to the system log which can be inspected in production builds. - **iOS**: Uses os_log instead of Swift.print, logs accessible via Console.app or Instruments - **Android**: Logs to Logcat (android.util.Log) When set to false, system logging is disabled on both platforms (only JavaScript console logging will occur if enabled). This is useful for debugging production apps (App Store/TestFlight builds on iOS, or production APKs on Android). | <code>true</code> | 8.42.0 |
|
|
326
|
-
| **`shakeMenu`** | <code>boolean</code> | Enable shake gesture
|
|
327
|
-
| **`allowShakeChannelSelector`** | <code>boolean</code> | Enable the shake gesture to show a channel selector menu for switching between update channels.
|
|
326
|
+
| **`shakeMenu`** | <code>boolean</code> | Enable the shake gesture while a preview session is active. Outside preview sessions this preview menu is ignored, unless {@link PluginsConfig.CapacitorUpdater.allowShakeChannelSelector} is enabled. | <code>false</code> | 7.5.0 |
|
|
327
|
+
| **`allowShakeChannelSelector`** | <code>boolean</code> | Enable the shake gesture to show a channel selector menu for switching between update channels. If {@link PluginsConfig.CapacitorUpdater.shakeMenu} is also enabled while a preview session is active, the shake menu includes both preview actions and channel switching. Only available for Android and iOS. | <code>false</code> | 8.43.0 |
|
|
328
328
|
|
|
329
329
|
### Examples
|
|
330
330
|
|
|
@@ -1818,19 +1818,15 @@ Use this to:
|
|
|
1818
1818
|
setShakeMenu(options: SetShakeMenuOptions) => Promise<void>
|
|
1819
1819
|
```
|
|
1820
1820
|
|
|
1821
|
-
Enable or disable the shake gesture menu
|
|
1821
|
+
Enable or disable the shake gesture menu.
|
|
1822
1822
|
|
|
1823
|
-
|
|
1824
|
-
-
|
|
1825
|
-
-
|
|
1826
|
-
-
|
|
1827
|
-
- Update status
|
|
1823
|
+
During preview sessions, users can shake their device to:
|
|
1824
|
+
- Reload the current preview
|
|
1825
|
+
- Leave the test app and return to the fallback bundle
|
|
1826
|
+
- Switch update channel, when {@link PluginsConfig.CapacitorUpdater.allowShakeChannelSelector} is also enabled
|
|
1828
1827
|
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
- Debug update flows
|
|
1832
|
-
- Switch between production and test bundles
|
|
1833
|
-
- Verify bundle installations
|
|
1828
|
+
Outside preview sessions, this preview menu is ignored. The channel selector can still be
|
|
1829
|
+
shown outside preview sessions when {@link PluginsConfig.CapacitorUpdater.allowShakeChannelSelector} is enabled.
|
|
1834
1830
|
|
|
1835
1831
|
**Important:** Disable this in production builds or only enable for internal testers.
|
|
1836
1832
|
|
|
@@ -1876,12 +1872,9 @@ setShakeChannelSelector(options: SetShakeChannelSelectorOptions) => Promise<void
|
|
|
1876
1872
|
|
|
1877
1873
|
Enable or disable the shake channel selector at runtime.
|
|
1878
1874
|
|
|
1879
|
-
When enabled
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
After selecting a channel, the app automatically checks for updates
|
|
1884
|
-
and downloads if available.
|
|
1875
|
+
When enabled, shaking the device can show a channel selector, including outside preview sessions.
|
|
1876
|
+
If {@link setShakeMenu} is also enabled while a preview session is active, the shake menu includes
|
|
1877
|
+
both preview actions and channel switching.
|
|
1885
1878
|
|
|
1886
1879
|
Can also be configured via {@link PluginsConfig.CapacitorUpdater.allowShakeChannelSelector}.
|
|
1887
1880
|
|
|
@@ -2386,7 +2379,7 @@ Result returned after requesting an immediate native auto-update check.
|
|
|
2386
2379
|
|
|
2387
2380
|
| Prop | Type | Description | Since |
|
|
2388
2381
|
| -------------------- | -------------------- | ----------------------------------------------- | ----- |
|
|
2389
|
-
| **`id`** | <code>
|
|
2382
|
+
| **`id`** | <code>number</code> | The channel ID | 7.5.0 |
|
|
2390
2383
|
| **`name`** | <code>string</code> | The channel name | 7.5.0 |
|
|
2391
2384
|
| **`public`** | <code>boolean</code> | Whether this is a public channel | 7.5.0 |
|
|
2392
2385
|
| **`allow_self_set`** | <code>boolean</code> | Whether devices can self-assign to this channel | 7.5.0 |
|
|
@@ -115,6 +115,7 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
115
115
|
private static final int SPLASH_SCREEN_RETRY_DELAY_MS = 100;
|
|
116
116
|
private static final int SPLASH_SCREEN_MAX_RETRIES = 20;
|
|
117
117
|
private static final long PENDING_BUNDLE_APP_READY_MIN_TIMEOUT_MS = 30000L;
|
|
118
|
+
private static final long PREVIEW_TRANSITION_LOADER_TIMEOUT_MS = 60000L;
|
|
118
119
|
static final int APPLICATION_EXIT_REASON_UNKNOWN = 0;
|
|
119
120
|
static final int APPLICATION_EXIT_REASON_EXIT_SELF = 1;
|
|
120
121
|
static final int APPLICATION_EXIT_REASON_SIGNALED = 2;
|
|
@@ -128,7 +129,7 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
128
129
|
static final int APPLICATION_EXIT_REASON_USER_REQUESTED = 10;
|
|
129
130
|
static final int APPLICATION_EXIT_REASON_DEPENDENCY_DIED = 12;
|
|
130
131
|
|
|
131
|
-
private final String pluginVersion = "8.47.
|
|
132
|
+
private final String pluginVersion = "8.47.7";
|
|
132
133
|
private static final String DELAY_CONDITION_PREFERENCES = "";
|
|
133
134
|
|
|
134
135
|
private SharedPreferences.Editor editor;
|
|
@@ -222,6 +223,9 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
222
223
|
private final Handler mainHandler = new Handler(Looper.getMainLooper());
|
|
223
224
|
private FrameLayout splashscreenLoaderOverlay;
|
|
224
225
|
private Runnable splashscreenTimeoutRunnable;
|
|
226
|
+
private FrameLayout previewTransitionLoaderOverlay;
|
|
227
|
+
private Runnable previewTransitionLoaderTimeoutRunnable;
|
|
228
|
+
private boolean previewTransitionLoaderRequested = false;
|
|
225
229
|
private WebViewListener webViewStatsListener;
|
|
226
230
|
|
|
227
231
|
private static final class FireAndForgetPluginCall extends PluginCall {
|
|
@@ -537,7 +541,9 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
537
541
|
logger.info("Using preview appId " + previewAppId);
|
|
538
542
|
}
|
|
539
543
|
this.shakeMenuEnabled = true;
|
|
540
|
-
this.shakeChannelSelectorEnabled =
|
|
544
|
+
this.shakeChannelSelectorEnabled = this.prefs.contains(PREVIEW_PREVIOUS_SHAKE_CHANNEL_SELECTOR_PREF_KEY)
|
|
545
|
+
? this.prefs.getBoolean(PREVIEW_PREVIOUS_SHAKE_CHANNEL_SELECTOR_PREF_KEY, false)
|
|
546
|
+
: this.shakeChannelSelectorEnabled;
|
|
541
547
|
}
|
|
542
548
|
boolean resetWhenUpdate = this.getConfig().getBoolean("resetWhenUpdate", true);
|
|
543
549
|
|
|
@@ -682,6 +688,7 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
682
688
|
if (this.autoSplashscreen) {
|
|
683
689
|
this.hideSplashscreen();
|
|
684
690
|
}
|
|
691
|
+
this.hidePreviewTransitionLoader("app-ready");
|
|
685
692
|
}
|
|
686
693
|
|
|
687
694
|
private void hideSplashscreen() {
|
|
@@ -793,6 +800,38 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
793
800
|
return requestToken == this.splashscreenInvocationToken;
|
|
794
801
|
}
|
|
795
802
|
|
|
803
|
+
private FrameLayout createLoaderOverlay(final Activity activity, final boolean blocksTouches, final int backgroundColor) {
|
|
804
|
+
final ProgressBar progressBar = new ProgressBar(activity);
|
|
805
|
+
progressBar.setIndeterminate(true);
|
|
806
|
+
|
|
807
|
+
final FrameLayout overlay = new FrameLayout(activity);
|
|
808
|
+
overlay.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
|
|
809
|
+
overlay.setClickable(blocksTouches);
|
|
810
|
+
overlay.setFocusable(blocksTouches);
|
|
811
|
+
overlay.setBackgroundColor(backgroundColor);
|
|
812
|
+
overlay.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
|
|
813
|
+
|
|
814
|
+
final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
|
|
815
|
+
ViewGroup.LayoutParams.WRAP_CONTENT,
|
|
816
|
+
ViewGroup.LayoutParams.WRAP_CONTENT
|
|
817
|
+
);
|
|
818
|
+
params.gravity = Gravity.CENTER;
|
|
819
|
+
overlay.addView(progressBar, params);
|
|
820
|
+
return overlay;
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
private void attachLoaderOverlay(final Activity activity, final FrameLayout overlay) {
|
|
824
|
+
final ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView();
|
|
825
|
+
decorView.addView(overlay);
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
private void removeLoaderOverlay(final FrameLayout overlay) {
|
|
829
|
+
final ViewGroup parent = (ViewGroup) overlay.getParent();
|
|
830
|
+
if (parent != null) {
|
|
831
|
+
parent.removeView(overlay);
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
|
|
796
835
|
private void addSplashscreenLoaderIfNeeded() {
|
|
797
836
|
if (!Boolean.TRUE.equals(this.autoSplashscreenLoader)) {
|
|
798
837
|
return;
|
|
@@ -809,26 +848,8 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
809
848
|
return;
|
|
810
849
|
}
|
|
811
850
|
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
FrameLayout overlay = new FrameLayout(activity);
|
|
816
|
-
overlay.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
|
|
817
|
-
overlay.setClickable(false);
|
|
818
|
-
overlay.setFocusable(false);
|
|
819
|
-
overlay.setBackgroundColor(Color.TRANSPARENT);
|
|
820
|
-
overlay.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
|
|
821
|
-
|
|
822
|
-
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
|
|
823
|
-
ViewGroup.LayoutParams.WRAP_CONTENT,
|
|
824
|
-
ViewGroup.LayoutParams.WRAP_CONTENT
|
|
825
|
-
);
|
|
826
|
-
params.gravity = Gravity.CENTER;
|
|
827
|
-
overlay.addView(progressBar, params);
|
|
828
|
-
|
|
829
|
-
ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView();
|
|
830
|
-
decorView.addView(overlay);
|
|
831
|
-
|
|
851
|
+
FrameLayout overlay = createLoaderOverlay(activity, false, Color.TRANSPARENT);
|
|
852
|
+
attachLoaderOverlay(activity, overlay);
|
|
832
853
|
this.splashscreenLoaderOverlay = overlay;
|
|
833
854
|
};
|
|
834
855
|
|
|
@@ -842,10 +863,7 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
842
863
|
private void removeSplashscreenLoader() {
|
|
843
864
|
Runnable removeLoader = () -> {
|
|
844
865
|
if (this.splashscreenLoaderOverlay != null) {
|
|
845
|
-
|
|
846
|
-
if (parent != null) {
|
|
847
|
-
parent.removeView(this.splashscreenLoaderOverlay);
|
|
848
|
-
}
|
|
866
|
+
removeLoaderOverlay(this.splashscreenLoaderOverlay);
|
|
849
867
|
this.splashscreenLoaderOverlay = null;
|
|
850
868
|
}
|
|
851
869
|
};
|
|
@@ -857,6 +875,84 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
857
875
|
}
|
|
858
876
|
}
|
|
859
877
|
|
|
878
|
+
private void showPreviewTransitionLoader(final String reason) {
|
|
879
|
+
this.previewTransitionLoaderRequested = true;
|
|
880
|
+
final Runnable showLoader = () -> {
|
|
881
|
+
if (!this.previewTransitionLoaderRequested) {
|
|
882
|
+
return;
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
if (this.previewTransitionLoaderOverlay != null) {
|
|
886
|
+
cancelPreviewTransitionLoaderTimeout();
|
|
887
|
+
schedulePreviewTransitionLoaderTimeout();
|
|
888
|
+
this.previewTransitionLoaderOverlay.bringToFront();
|
|
889
|
+
return;
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
final Activity activity = getActivity();
|
|
893
|
+
if (activity == null) {
|
|
894
|
+
logger.warn("Preview transition loader unavailable: activity missing for " + reason);
|
|
895
|
+
this.previewTransitionLoaderRequested = false;
|
|
896
|
+
return;
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
cancelPreviewTransitionLoaderTimeout();
|
|
900
|
+
schedulePreviewTransitionLoaderTimeout();
|
|
901
|
+
|
|
902
|
+
final FrameLayout overlay = createLoaderOverlay(activity, true, Color.argb(46, 0, 0, 0));
|
|
903
|
+
attachLoaderOverlay(activity, overlay);
|
|
904
|
+
this.previewTransitionLoaderOverlay = overlay;
|
|
905
|
+
logger.info("Preview transition loader shown: " + reason);
|
|
906
|
+
};
|
|
907
|
+
|
|
908
|
+
if (Looper.myLooper() == Looper.getMainLooper()) {
|
|
909
|
+
showLoader.run();
|
|
910
|
+
} else {
|
|
911
|
+
this.mainHandler.post(showLoader);
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
private void hidePreviewTransitionLoader(final String reason) {
|
|
916
|
+
if (
|
|
917
|
+
!this.previewTransitionLoaderRequested &&
|
|
918
|
+
this.previewTransitionLoaderOverlay == null &&
|
|
919
|
+
this.previewTransitionLoaderTimeoutRunnable == null
|
|
920
|
+
) {
|
|
921
|
+
return;
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
final Runnable hideLoader = () -> {
|
|
925
|
+
this.previewTransitionLoaderRequested = false;
|
|
926
|
+
cancelPreviewTransitionLoaderTimeout();
|
|
927
|
+
if (this.previewTransitionLoaderOverlay == null) {
|
|
928
|
+
return;
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
removeLoaderOverlay(this.previewTransitionLoaderOverlay);
|
|
932
|
+
this.previewTransitionLoaderOverlay = null;
|
|
933
|
+
logger.info("Preview transition loader hidden: " + reason);
|
|
934
|
+
};
|
|
935
|
+
|
|
936
|
+
if (Looper.myLooper() == Looper.getMainLooper()) {
|
|
937
|
+
hideLoader.run();
|
|
938
|
+
} else {
|
|
939
|
+
this.mainHandler.post(hideLoader);
|
|
940
|
+
}
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
private void schedulePreviewTransitionLoaderTimeout() {
|
|
944
|
+
cancelPreviewTransitionLoaderTimeout();
|
|
945
|
+
this.previewTransitionLoaderTimeoutRunnable = () -> hidePreviewTransitionLoader("preview-transition-timeout");
|
|
946
|
+
this.mainHandler.postDelayed(this.previewTransitionLoaderTimeoutRunnable, PREVIEW_TRANSITION_LOADER_TIMEOUT_MS);
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
private void cancelPreviewTransitionLoaderTimeout() {
|
|
950
|
+
if (this.previewTransitionLoaderTimeoutRunnable != null) {
|
|
951
|
+
this.mainHandler.removeCallbacks(this.previewTransitionLoaderTimeoutRunnable);
|
|
952
|
+
this.previewTransitionLoaderTimeoutRunnable = null;
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
|
|
860
956
|
private void scheduleSplashscreenTimeout() {
|
|
861
957
|
if (this.autoSplashscreenTimeout == null || this.autoSplashscreenTimeout <= 0) {
|
|
862
958
|
return;
|
|
@@ -2325,6 +2421,7 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
2325
2421
|
@PluginMethod
|
|
2326
2422
|
public void startPreviewSession(final PluginCall call) {
|
|
2327
2423
|
if (!Boolean.TRUE.equals(this.allowPreview)) {
|
|
2424
|
+
this.hidePreviewTransitionLoader("preview-session-not-allowed");
|
|
2328
2425
|
logger.error("startPreviewSession not allowed set allowPreview in your config to true to enable it");
|
|
2329
2426
|
call.reject("startPreviewSession not allowed");
|
|
2330
2427
|
return;
|
|
@@ -2333,6 +2430,7 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
2333
2430
|
final String rawPayloadUrl = call.getString("payloadUrl");
|
|
2334
2431
|
final String previewPayloadUrl = this.normalizePreviewPayloadUrl(rawPayloadUrl);
|
|
2335
2432
|
if (this.hasPreviewPayloadUrl(rawPayloadUrl) && previewPayloadUrl == null) {
|
|
2433
|
+
this.hidePreviewTransitionLoader("preview-session-invalid-payload");
|
|
2336
2434
|
logger.error("startPreviewSession called with invalid payloadUrl");
|
|
2337
2435
|
call.reject("Invalid preview payloadUrl");
|
|
2338
2436
|
return;
|
|
@@ -2342,6 +2440,7 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
2342
2440
|
if (!Boolean.TRUE.equals(this.previewSessionEnabled)) {
|
|
2343
2441
|
final BundleInfo current = this.implementation.getCurrentBundle();
|
|
2344
2442
|
if (!this.implementation.setPreviewFallbackBundle(current.getId())) {
|
|
2443
|
+
this.hidePreviewTransitionLoader("preview-session-fallback-failed");
|
|
2345
2444
|
logger.error("Could not save current bundle as preview fallback");
|
|
2346
2445
|
call.reject("Could not save current bundle as preview fallback");
|
|
2347
2446
|
return;
|
|
@@ -2386,17 +2485,18 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
2386
2485
|
this.editor.remove(PREVIEW_PAYLOAD_URL_PREF_KEY);
|
|
2387
2486
|
}
|
|
2388
2487
|
|
|
2488
|
+
this.hidePreviewTransitionLoader("preview-session-started");
|
|
2389
2489
|
this.previewSessionEnabled = true;
|
|
2390
2490
|
this.previewSessionAlertPending = true;
|
|
2391
2491
|
this.implementation.previewSession = true;
|
|
2392
2492
|
this.shakeMenuEnabled = true;
|
|
2393
|
-
this.shakeChannelSelectorEnabled = false;
|
|
2394
2493
|
this.editor.putBoolean(PREVIEW_SESSION_PREF_KEY, true);
|
|
2395
2494
|
this.editor.putBoolean(PREVIEW_SESSION_ALERT_PENDING_PREF_KEY, true);
|
|
2396
2495
|
this.editor.apply();
|
|
2397
2496
|
this.ensureShakeMenuStarted();
|
|
2398
2497
|
call.resolve();
|
|
2399
2498
|
} catch (final Exception e) {
|
|
2499
|
+
this.hidePreviewTransitionLoader("preview-session-failed");
|
|
2400
2500
|
logger.error("Could not start preview session " + e.getMessage());
|
|
2401
2501
|
call.reject("Could not start preview session", e);
|
|
2402
2502
|
}
|
|
@@ -2406,8 +2506,10 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
2406
2506
|
public boolean leavePreviewSessionFromShakeMenu() {
|
|
2407
2507
|
final BundleInfo previewBundle = this.implementation.getCurrentBundle();
|
|
2408
2508
|
|
|
2509
|
+
this.showPreviewTransitionLoader("leave-preview-session");
|
|
2409
2510
|
final boolean didReset = this.resetToPreviewFallbackBundle();
|
|
2410
2511
|
if (!didReset) {
|
|
2512
|
+
this.hidePreviewTransitionLoader("leave-preview-session-failed");
|
|
2411
2513
|
return false;
|
|
2412
2514
|
}
|
|
2413
2515
|
|
|
@@ -2419,8 +2521,10 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
2419
2521
|
}
|
|
2420
2522
|
|
|
2421
2523
|
private boolean leavePreviewSessionForIncomingPreviewLink() {
|
|
2524
|
+
this.showPreviewTransitionLoader("incoming-preview-deeplink");
|
|
2422
2525
|
final BundleInfo previewBundle = this.implementation.getCurrentBundle();
|
|
2423
2526
|
final BundleInfo previewFallbackBundle = this.implementation.getPreviewFallbackBundle();
|
|
2527
|
+
boolean didReload = false;
|
|
2424
2528
|
|
|
2425
2529
|
try {
|
|
2426
2530
|
if (previewFallbackBundle == null || previewFallbackBundle.isErrorStatus()) {
|
|
@@ -2443,6 +2547,7 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
2443
2547
|
this.restoreLiveBundleStateAfterFailedReload();
|
|
2444
2548
|
return false;
|
|
2445
2549
|
}
|
|
2550
|
+
didReload = true;
|
|
2446
2551
|
|
|
2447
2552
|
this.endPreviewSession(true);
|
|
2448
2553
|
final BundleInfo restoredNextBundle = this.implementation.getNextBundle();
|
|
@@ -2450,6 +2555,9 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
2450
2555
|
return true;
|
|
2451
2556
|
} finally {
|
|
2452
2557
|
this.clearIncomingPreviewTransition();
|
|
2558
|
+
if (!didReload) {
|
|
2559
|
+
this.hidePreviewTransitionLoader("incoming-preview-deeplink-failed");
|
|
2560
|
+
}
|
|
2453
2561
|
}
|
|
2454
2562
|
}
|
|
2455
2563
|
|
|
@@ -2467,10 +2575,12 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
2467
2575
|
}
|
|
2468
2576
|
|
|
2469
2577
|
this.isLeavingPreviewForIncomingLink = true;
|
|
2578
|
+
this.showPreviewTransitionLoader("preview-launch-deeplink");
|
|
2470
2579
|
logger.info("Preview deeplink launch detected while preview session is active; restoring fallback before initial load");
|
|
2471
2580
|
if (!this.leavePreviewSessionWithoutReload()) {
|
|
2472
2581
|
logger.error("Could not leave preview session before initial preview deeplink routing");
|
|
2473
2582
|
this.isLeavingPreviewForIncomingLink = false;
|
|
2583
|
+
this.hidePreviewTransitionLoader("preview-launch-deeplink-failed");
|
|
2474
2584
|
}
|
|
2475
2585
|
}
|
|
2476
2586
|
|
|
@@ -2519,12 +2629,19 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
2519
2629
|
}
|
|
2520
2630
|
|
|
2521
2631
|
public boolean reloadPreviewSessionFromShakeMenu() {
|
|
2632
|
+
this.showPreviewTransitionLoader("reload-preview-session");
|
|
2633
|
+
final boolean didReload;
|
|
2522
2634
|
final String payloadUrl = this.storedPreviewPayloadUrl();
|
|
2523
2635
|
if (payloadUrl != null) {
|
|
2524
|
-
|
|
2636
|
+
didReload = this.refreshPreviewSessionFromPayloadUrl(payloadUrl);
|
|
2637
|
+
} else {
|
|
2638
|
+
didReload = this.reloadWithoutWaitingForAppReady();
|
|
2525
2639
|
}
|
|
2526
2640
|
|
|
2527
|
-
|
|
2641
|
+
if (!didReload) {
|
|
2642
|
+
this.hidePreviewTransitionLoader("reload-preview-session-failed");
|
|
2643
|
+
}
|
|
2644
|
+
return didReload;
|
|
2528
2645
|
}
|
|
2529
2646
|
|
|
2530
2647
|
public boolean hasActivePreviewSession() {
|
|
@@ -2581,6 +2698,7 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
2581
2698
|
}
|
|
2582
2699
|
this.shakeMenuEnabled = previousShakeMenuEnabled;
|
|
2583
2700
|
this.shakeChannelSelectorEnabled = previousShakeChannelSelectorEnabled;
|
|
2701
|
+
this.syncShakeMenuLifecycle();
|
|
2584
2702
|
this.implementation.setPreviewFallbackBundle(null);
|
|
2585
2703
|
this.clearPreviewSessionPreferences();
|
|
2586
2704
|
logger.info("Preview session ended");
|
|
@@ -2605,8 +2723,10 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
2605
2723
|
this.previewSessionAlertPending = false;
|
|
2606
2724
|
this.isLeavingPreviewForIncomingLink = false;
|
|
2607
2725
|
this.implementation.previewSession = false;
|
|
2726
|
+
this.hidePreviewTransitionLoader("preview-session-disabled");
|
|
2608
2727
|
this.shakeMenuEnabled = this.getConfig().getBoolean("shakeMenu", false);
|
|
2609
2728
|
this.shakeChannelSelectorEnabled = this.getConfig().getBoolean("allowShakeChannelSelector", false);
|
|
2729
|
+
this.syncShakeMenuLifecycle();
|
|
2610
2730
|
this.clearPreviewSessionPreferences();
|
|
2611
2731
|
}
|
|
2612
2732
|
|
|
@@ -2829,6 +2949,7 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
2829
2949
|
this.implementation.previewSession = false;
|
|
2830
2950
|
this.shakeMenuEnabled = this.getConfig().getBoolean("shakeMenu", false);
|
|
2831
2951
|
this.shakeChannelSelectorEnabled = this.getConfig().getBoolean("allowShakeChannelSelector", false);
|
|
2952
|
+
this.syncShakeMenuLifecycle();
|
|
2832
2953
|
this.restorePreviewPreviousAppId();
|
|
2833
2954
|
this.restorePreviewPreviousDefaultChannel();
|
|
2834
2955
|
this.implementation.setPreviewFallbackBundle(null);
|
|
@@ -2859,6 +2980,24 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
2859
2980
|
}
|
|
2860
2981
|
}
|
|
2861
2982
|
|
|
2983
|
+
private void syncShakeMenuLifecycle() {
|
|
2984
|
+
if (this.shouldListenForShake()) {
|
|
2985
|
+
this.ensureShakeMenuStarted();
|
|
2986
|
+
} else if (shakeMenu != null) {
|
|
2987
|
+
try {
|
|
2988
|
+
shakeMenu.stop();
|
|
2989
|
+
shakeMenu = null;
|
|
2990
|
+
logger.info("Shake menu stopped");
|
|
2991
|
+
} catch (Exception e) {
|
|
2992
|
+
logger.error("Failed to stop shake menu: " + e.getMessage());
|
|
2993
|
+
}
|
|
2994
|
+
}
|
|
2995
|
+
}
|
|
2996
|
+
|
|
2997
|
+
private boolean shouldListenForShake() {
|
|
2998
|
+
return Boolean.TRUE.equals(this.shakeMenuEnabled) || Boolean.TRUE.equals(this.shakeChannelSelectorEnabled);
|
|
2999
|
+
}
|
|
3000
|
+
|
|
2862
3001
|
private void showPreviewSessionNoticeIfNeeded() {
|
|
2863
3002
|
if (!Boolean.TRUE.equals(this.previewSessionEnabled) || !Boolean.TRUE.equals(this.previewSessionAlertPending)) {
|
|
2864
3003
|
return;
|
|
@@ -3337,6 +3476,7 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
3337
3476
|
this.semaphoreDown();
|
|
3338
3477
|
logger.info("semaphoreReady countDown done");
|
|
3339
3478
|
this.clearIncomingPreviewTransition();
|
|
3479
|
+
this.hidePreviewTransitionLoader("notify-app-ready");
|
|
3340
3480
|
final JSObject ret = new JSObject();
|
|
3341
3481
|
ret.put("bundle", InternalUtils.mapToJSObject(bundle.toJSONMap()));
|
|
3342
3482
|
call.resolve(ret);
|
|
@@ -4185,6 +4325,7 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
4185
4325
|
}
|
|
4186
4326
|
|
|
4187
4327
|
this.isLeavingPreviewForIncomingLink = true;
|
|
4328
|
+
this.showPreviewTransitionLoader("incoming-preview-deeplink");
|
|
4188
4329
|
if (getActivity() != null) {
|
|
4189
4330
|
getActivity().setIntent(intent);
|
|
4190
4331
|
}
|
|
@@ -4194,6 +4335,7 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
4194
4335
|
if (!didLeave) {
|
|
4195
4336
|
logger.error("Could not leave preview session before routing incoming preview deeplink");
|
|
4196
4337
|
this.isLeavingPreviewForIncomingLink = false;
|
|
4338
|
+
this.hidePreviewTransitionLoader("incoming-preview-deeplink-failed");
|
|
4197
4339
|
}
|
|
4198
4340
|
});
|
|
4199
4341
|
}
|
|
@@ -4214,13 +4356,8 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
4214
4356
|
}
|
|
4215
4357
|
|
|
4216
4358
|
// Initialize shake menu if enabled and activity is BridgeActivity
|
|
4217
|
-
if (
|
|
4218
|
-
|
|
4219
|
-
shakeMenu = new ShakeMenu(this, (com.getcapacitor.BridgeActivity) getActivity(), logger);
|
|
4220
|
-
logger.info("Shake menu initialized");
|
|
4221
|
-
} catch (Exception e) {
|
|
4222
|
-
logger.error("Failed to initialize shake menu: " + e.getMessage());
|
|
4223
|
-
}
|
|
4359
|
+
if (this.shouldListenForShake()) {
|
|
4360
|
+
this.ensureShakeMenuStarted();
|
|
4224
4361
|
}
|
|
4225
4362
|
} catch (Exception e) {
|
|
4226
4363
|
logger.error("Failed to run handleOnStart: " + e.getMessage());
|
|
@@ -4279,23 +4416,7 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
4279
4416
|
this.shakeMenuEnabled = enabled;
|
|
4280
4417
|
logger.info("Shake menu " + (enabled ? "enabled" : "disabled"));
|
|
4281
4418
|
|
|
4282
|
-
|
|
4283
|
-
if (enabled && getActivity() instanceof com.getcapacitor.BridgeActivity && shakeMenu == null) {
|
|
4284
|
-
try {
|
|
4285
|
-
shakeMenu = new ShakeMenu(this, (com.getcapacitor.BridgeActivity) getActivity(), logger);
|
|
4286
|
-
logger.info("Shake menu initialized");
|
|
4287
|
-
} catch (Exception e) {
|
|
4288
|
-
logger.error("Failed to initialize shake menu: " + e.getMessage());
|
|
4289
|
-
}
|
|
4290
|
-
} else if (!enabled && shakeMenu != null) {
|
|
4291
|
-
try {
|
|
4292
|
-
shakeMenu.stop();
|
|
4293
|
-
shakeMenu = null;
|
|
4294
|
-
logger.info("Shake menu stopped");
|
|
4295
|
-
} catch (Exception e) {
|
|
4296
|
-
logger.error("Failed to stop shake menu: " + e.getMessage());
|
|
4297
|
-
}
|
|
4298
|
-
}
|
|
4419
|
+
this.syncShakeMenuLifecycle();
|
|
4299
4420
|
|
|
4300
4421
|
call.resolve();
|
|
4301
4422
|
}
|
|
@@ -4323,6 +4444,7 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
4323
4444
|
|
|
4324
4445
|
this.shakeChannelSelectorEnabled = enabled;
|
|
4325
4446
|
logger.info("Shake channel selector " + (enabled ? "enabled" : "disabled"));
|
|
4447
|
+
this.syncShakeMenuLifecycle();
|
|
4326
4448
|
call.resolve();
|
|
4327
4449
|
}
|
|
4328
4450
|
|
|
@@ -1903,59 +1903,38 @@ public class CapgoUpdater {
|
|
|
1903
1903
|
String data = responseBody.string();
|
|
1904
1904
|
|
|
1905
1905
|
try {
|
|
1906
|
-
Map<String, Object> ret =
|
|
1906
|
+
Map<String, Object> ret = parseListChannelsResponse(data);
|
|
1907
1907
|
|
|
1908
|
+
logger.info("Channels listed successfully");
|
|
1909
|
+
callback.callback(ret);
|
|
1910
|
+
} catch (JSONException arrayException) {
|
|
1911
|
+
// If not an array, try to parse as error object
|
|
1908
1912
|
try {
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
List<Map<String, Object>> channelsList = new ArrayList<>();
|
|
1912
|
-
|
|
1913
|
-
for (int i = 0; i < channelsJson.length(); i++) {
|
|
1914
|
-
JSONObject channelJson = channelsJson.getJSONObject(i);
|
|
1915
|
-
Map<String, Object> channel = new HashMap<>();
|
|
1916
|
-
channel.put("id", channelJson.optString("id", ""));
|
|
1917
|
-
channel.put("name", channelJson.optString("name", ""));
|
|
1918
|
-
channel.put("public", channelJson.optBoolean("public", false));
|
|
1919
|
-
channel.put("allow_self_set", channelJson.optBoolean("allow_self_set", false));
|
|
1920
|
-
channelsList.add(channel);
|
|
1921
|
-
}
|
|
1922
|
-
|
|
1923
|
-
// Wrap in channels object for JS API
|
|
1924
|
-
ret.put("channels", channelsList);
|
|
1925
|
-
|
|
1926
|
-
logger.info("Channels listed successfully");
|
|
1927
|
-
callback.callback(ret);
|
|
1928
|
-
} catch (JSONException arrayException) {
|
|
1929
|
-
// If not an array, try to parse as error object
|
|
1930
|
-
try {
|
|
1931
|
-
JSONObject json = new JSONObject(data);
|
|
1932
|
-
if (json.has("error")) {
|
|
1933
|
-
Map<String, Object> retError = new HashMap<>();
|
|
1934
|
-
retError.put("error", json.getString("error"));
|
|
1935
|
-
if (json.has("message")) {
|
|
1936
|
-
retError.put("message", json.getString("message"));
|
|
1937
|
-
} else {
|
|
1938
|
-
retError.put("message", "server did not provide a message");
|
|
1939
|
-
}
|
|
1940
|
-
callback.callback(retError);
|
|
1941
|
-
return;
|
|
1942
|
-
}
|
|
1913
|
+
JSONObject json = new JSONObject(data);
|
|
1914
|
+
if (json.has("error")) {
|
|
1943
1915
|
Map<String, Object> retError = new HashMap<>();
|
|
1944
|
-
retError.put("
|
|
1945
|
-
|
|
1916
|
+
retError.put("error", json.getString("error"));
|
|
1917
|
+
if (json.has("message")) {
|
|
1918
|
+
retError.put("message", json.getString("message"));
|
|
1919
|
+
} else {
|
|
1920
|
+
retError.put("message", "server did not provide a message");
|
|
1921
|
+
}
|
|
1946
1922
|
callback.callback(retError);
|
|
1947
1923
|
return;
|
|
1948
|
-
} catch (JSONException objException) {
|
|
1949
|
-
// If neither array nor object, throw parse error
|
|
1950
|
-
arrayException.addSuppressed(objException);
|
|
1951
|
-
throw arrayException;
|
|
1952
1924
|
}
|
|
1925
|
+
Map<String, Object> retError = new HashMap<>();
|
|
1926
|
+
retError.put("message", "Unexpected channels response format");
|
|
1927
|
+
retError.put("error", "parse_error");
|
|
1928
|
+
callback.callback(retError);
|
|
1929
|
+
return;
|
|
1930
|
+
} catch (JSONException objException) {
|
|
1931
|
+
// If neither array nor object, throw parse error
|
|
1932
|
+
arrayException.addSuppressed(objException);
|
|
1933
|
+
Map<String, Object> retError = new HashMap<>();
|
|
1934
|
+
retError.put("message", "JSON parse error: " + arrayException.getMessage());
|
|
1935
|
+
retError.put("error", "parse_error");
|
|
1936
|
+
callback.callback(retError);
|
|
1953
1937
|
}
|
|
1954
|
-
} catch (JSONException e) {
|
|
1955
|
-
Map<String, Object> retError = new HashMap<>();
|
|
1956
|
-
retError.put("message", "JSON parse error: " + e.getMessage());
|
|
1957
|
-
retError.put("error", "parse_error");
|
|
1958
|
-
callback.callback(retError);
|
|
1959
1938
|
}
|
|
1960
1939
|
}
|
|
1961
1940
|
}
|
|
@@ -1963,6 +1942,29 @@ public class CapgoUpdater {
|
|
|
1963
1942
|
);
|
|
1964
1943
|
}
|
|
1965
1944
|
|
|
1945
|
+
static Map<String, Object> parseListChannelsResponse(final String data) throws JSONException {
|
|
1946
|
+
JSONArray channelsJson = new JSONArray(data);
|
|
1947
|
+
List<Map<String, Object>> channelsList = new ArrayList<>();
|
|
1948
|
+
|
|
1949
|
+
for (int i = 0; i < channelsJson.length(); i++) {
|
|
1950
|
+
JSONObject channelJson = channelsJson.getJSONObject(i);
|
|
1951
|
+
Object channelId = channelJson.get("id");
|
|
1952
|
+
if (!(channelId instanceof Number)) {
|
|
1953
|
+
throw new JSONException("Channel id must be a number");
|
|
1954
|
+
}
|
|
1955
|
+
Map<String, Object> channel = new HashMap<>();
|
|
1956
|
+
channel.put("id", channelId);
|
|
1957
|
+
channel.put("name", channelJson.optString("name", ""));
|
|
1958
|
+
channel.put("public", channelJson.optBoolean("public", false));
|
|
1959
|
+
channel.put("allow_self_set", channelJson.optBoolean("allow_self_set", false));
|
|
1960
|
+
channelsList.add(channel);
|
|
1961
|
+
}
|
|
1962
|
+
|
|
1963
|
+
Map<String, Object> ret = new HashMap<>();
|
|
1964
|
+
ret.put("channels", channelsList);
|
|
1965
|
+
return ret;
|
|
1966
|
+
}
|
|
1967
|
+
|
|
1966
1968
|
public void sendStats(final String action) {
|
|
1967
1969
|
this.sendStats(action, this.getCurrentBundle().getVersionName());
|
|
1968
1970
|
}
|