@capgo/capacitor-updater 8.47.5 → 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.
@@ -115,15 +115,13 @@ public class DownloadService extends Worker {
115
115
  }
116
116
 
117
117
  StringBuilder sanitized = new StringBuilder();
118
- value
119
- .codePoints()
120
- .forEach((cp) -> {
121
- boolean isVisibleAscii = cp >= 0x20 && cp <= 0x7E;
122
- boolean isIso88591 = cp >= 0xA0 && cp <= 0xFF;
123
- if (isVisibleAscii || isIso88591) {
124
- sanitized.appendCodePoint(cp);
125
- }
126
- });
118
+ value.codePoints().forEach((cp) -> {
119
+ boolean isVisibleAscii = cp >= 0x20 && cp <= 0x7E;
120
+ boolean isIso88591 = cp >= 0xA0 && cp <= 0xFF;
121
+ if (isVisibleAscii || isIso88591) {
122
+ sanitized.appendCodePoint(cp);
123
+ }
124
+ });
127
125
 
128
126
  String result = sanitized.toString().trim();
129
127
  return result.isEmpty() ? "unknown" : result;
@@ -255,27 +253,26 @@ public class DownloadService extends Worker {
255
253
  .post(RequestBody.create(json.toString(), MediaType.get("application/json")))
256
254
  .build();
257
255
 
258
- sharedClient
259
- .newCall(request)
260
- .enqueue(
261
- new Callback() {
262
- @Override
263
- public void onFailure(@NonNull Call call, @NonNull IOException e) {
264
- if (logger != null) {
265
- logger.error("Failed to send stats: " + e.getMessage());
266
- }
256
+ sharedClient.newCall(request).enqueue(
257
+ new Callback() {
258
+ @Override
259
+ public void onFailure(@NonNull Call call, @NonNull IOException e) {
260
+ if (logger != null) {
261
+ logger.error("Failed to send stats: " + e.getMessage());
267
262
  }
263
+ }
268
264
 
269
- @Override
270
- public void onResponse(@NonNull Call call, @NonNull Response response) {
271
- try (ResponseBody body = response.body()) {
272
- // nothing else to do, just closing body
273
- } catch (Exception ignored) {} finally {
274
- response.close();
275
- }
265
+ @Override
266
+ public void onResponse(@NonNull Call call, @NonNull Response response) {
267
+ try (ResponseBody body = response.body()) {
268
+ // nothing else to do, just closing body
269
+ } catch (Exception ignored) {
270
+ } finally {
271
+ response.close();
276
272
  }
277
273
  }
278
- );
274
+ }
275
+ );
279
276
  } catch (Exception e) {
280
277
  if (logger != null) {
281
278
  logger.error("sendStatsAsync error: " + e.getMessage());
@@ -26,6 +26,10 @@ import org.json.JSONArray;
26
26
 
27
27
  public class ShakeMenu implements ShakeDetector.Listener {
28
28
 
29
+ private interface PreviewMenuAction {
30
+ boolean run();
31
+ }
32
+
29
33
  private CapacitorUpdaterPlugin plugin;
30
34
  private BridgeActivity activity;
31
35
  private ShakeDetector shakeDetector;
@@ -52,9 +56,14 @@ public class ShakeMenu implements ShakeDetector.Listener {
52
56
  public void onShakeDetected() {
53
57
  logger.info("Shake detected");
54
58
 
55
- // Check if shake menu is enabled
56
- if (!plugin.shakeMenuEnabled) {
57
- logger.info("Shake menu is disabled");
59
+ boolean canShowPreviewMenu = Boolean.TRUE.equals(plugin.shakeMenuEnabled) && plugin.hasActivePreviewSession();
60
+ boolean canShowChannelSelector = Boolean.TRUE.equals(plugin.shakeChannelSelectorEnabled);
61
+ if (!canShowPreviewMenu && !canShowChannelSelector) {
62
+ if (Boolean.TRUE.equals(plugin.shakeMenuEnabled)) {
63
+ logger.info("Shake preview menu ignored because no preview session is active");
64
+ } else {
65
+ logger.info("Shake menu is disabled");
66
+ }
58
67
  return;
59
68
  }
60
69
 
@@ -66,12 +75,10 @@ public class ShakeMenu implements ShakeDetector.Listener {
66
75
 
67
76
  isShowing = true;
68
77
 
69
- if (plugin.hasActivePreviewSession()) {
78
+ if (canShowPreviewMenu) {
70
79
  showDefaultMenu();
71
- } else if (plugin.shakeChannelSelectorEnabled) {
72
- showChannelSelector();
73
80
  } else {
74
- showDefaultMenu();
81
+ showChannelSelector();
75
82
  }
76
83
  }
77
84
 
@@ -79,7 +86,12 @@ public class ShakeMenu implements ShakeDetector.Listener {
79
86
  activity.runOnUiThread(() -> {
80
87
  try {
81
88
  if (!plugin.hasActivePreviewSession()) {
82
- showConfiguredDefaultMenu();
89
+ logger.info("Shake preview menu ignored because no preview session is active");
90
+ isShowing = false;
91
+ return;
92
+ }
93
+ if (Boolean.TRUE.equals(plugin.shakeChannelSelectorEnabled)) {
94
+ showCombinedPreviewMenu();
83
95
  return;
84
96
  }
85
97
  String appName = activity.getPackageManager().getApplicationLabel(activity.getApplicationInfo()).toString();
@@ -111,49 +123,19 @@ public class ShakeMenu implements ShakeDetector.Listener {
111
123
  AlertDialog dialog = builder.create();
112
124
  dialog.setOnDismissListener((dialogInterface) -> isShowing = false);
113
125
  dialog.show();
114
- dialog
115
- .getButton(AlertDialog.BUTTON_POSITIVE)
116
- .setOnClickListener((view) -> {
117
- setPreviewMenuButtonsEnabled(dialog, false);
118
- new Thread(() -> {
119
- try {
120
- if (!plugin.leavePreviewSessionFromShakeMenu()) {
121
- activity.runOnUiThread(() -> showError("Could not leave the test app."));
122
- }
123
- } catch (Exception e) {
124
- logger.error("Error leaving test app: " + e.getMessage());
125
- activity.runOnUiThread(() -> showError("Error leaving test app: " + e.getMessage()));
126
- } finally {
127
- activity.runOnUiThread(() -> {
128
- dialog.dismiss();
129
- isShowing = false;
130
- });
131
- }
132
- })
133
- .start();
134
- });
135
- dialog
136
- .getButton(AlertDialog.BUTTON_NEUTRAL)
137
- .setOnClickListener((view) -> {
138
- setPreviewMenuButtonsEnabled(dialog, false);
139
- new Thread(() -> {
140
- try {
141
- logger.info("Reloading webview");
142
- if (!plugin.reloadPreviewSessionFromShakeMenu()) {
143
- activity.runOnUiThread(() -> showError("Could not reload the test app."));
144
- }
145
- } catch (Exception e) {
146
- logger.error("Error in Reload action: " + e.getMessage());
147
- activity.runOnUiThread(() -> showError("Error reloading test app: " + e.getMessage()));
148
- } finally {
149
- activity.runOnUiThread(() -> {
150
- dialog.dismiss();
151
- isShowing = false;
152
- });
153
- }
154
- })
155
- .start();
156
- });
126
+ dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener((view) -> {
127
+ setPreviewMenuButtonsEnabled(dialog, false);
128
+ runPreviewMenuAction(dialog, "Could not leave the test app.", "Error leaving test app: ", () ->
129
+ plugin.leavePreviewSessionFromShakeMenu()
130
+ );
131
+ });
132
+ dialog.getButton(AlertDialog.BUTTON_NEUTRAL).setOnClickListener((view) -> {
133
+ setPreviewMenuButtonsEnabled(dialog, false);
134
+ logger.info("Reloading webview");
135
+ runPreviewMenuAction(dialog, "Could not reload the test app.", "Error reloading test app: ", () ->
136
+ plugin.reloadPreviewSessionFromShakeMenu()
137
+ );
138
+ });
157
139
  } catch (Exception e) {
158
140
  logger.error("Error showing shake menu: " + e.getMessage());
159
141
  isShowing = false;
@@ -161,6 +143,74 @@ public class ShakeMenu implements ShakeDetector.Listener {
161
143
  });
162
144
  }
163
145
 
146
+ private void showCombinedPreviewMenu() {
147
+ try {
148
+ String appName = activity.getPackageManager().getApplicationLabel(activity.getApplicationInfo()).toString();
149
+ String title = "Preview " + appName + " Menu";
150
+ String message = "Reload or leave the current preview, or switch update channel.";
151
+ String[] actions = { "Reload preview", "Leave test app", "Switch channel" };
152
+ final boolean[] openingChannelSelector = { false };
153
+ final boolean[] previewActionRunning = { false };
154
+
155
+ AlertDialog.Builder builder = new AlertDialog.Builder(activity);
156
+ builder.setTitle(title);
157
+ builder.setMessage(message);
158
+ builder.setItems(actions, (dialogInterface, which) -> {
159
+ AlertDialog dialog = (AlertDialog) dialogInterface;
160
+ if (which == 0) {
161
+ previewActionRunning[0] = true;
162
+ logger.info("Reloading webview");
163
+ runPreviewMenuAction(dialog, "Could not reload the test app.", "Error reloading test app: ", () ->
164
+ plugin.reloadPreviewSessionFromShakeMenu()
165
+ );
166
+ } else if (which == 1) {
167
+ previewActionRunning[0] = true;
168
+ runPreviewMenuAction(dialog, "Could not leave the test app.", "Error leaving test app: ", () ->
169
+ plugin.leavePreviewSessionFromShakeMenu()
170
+ );
171
+ } else {
172
+ openingChannelSelector[0] = true;
173
+ dialog.dismiss();
174
+ showChannelSelector();
175
+ }
176
+ });
177
+ builder.setNegativeButton("Close menu", (dialog, id) -> {
178
+ logger.info("Shake menu cancelled");
179
+ dialog.dismiss();
180
+ isShowing = false;
181
+ });
182
+
183
+ AlertDialog dialog = builder.create();
184
+ dialog.setOnDismissListener((dialogInterface) -> {
185
+ if (!openingChannelSelector[0] && !previewActionRunning[0]) {
186
+ isShowing = false;
187
+ }
188
+ });
189
+ dialog.show();
190
+ } catch (Exception e) {
191
+ logger.error("Error showing combined shake menu: " + e.getMessage());
192
+ isShowing = false;
193
+ }
194
+ }
195
+
196
+ private void runPreviewMenuAction(AlertDialog dialog, String failureMessage, String errorPrefix, PreviewMenuAction action) {
197
+ new Thread(() -> {
198
+ try {
199
+ if (!action.run()) {
200
+ activity.runOnUiThread(() -> showError(failureMessage));
201
+ }
202
+ } catch (Exception e) {
203
+ logger.error(errorPrefix + e.getMessage());
204
+ activity.runOnUiThread(() -> showError(errorPrefix + e.getMessage()));
205
+ } finally {
206
+ activity.runOnUiThread(() -> {
207
+ dialog.dismiss();
208
+ isShowing = false;
209
+ });
210
+ }
211
+ }).start();
212
+ }
213
+
164
214
  private void setPreviewMenuButtonsEnabled(AlertDialog dialog, boolean enabled) {
165
215
  dialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(enabled);
166
216
  dialog.getButton(AlertDialog.BUTTON_NEUTRAL).setEnabled(enabled);
@@ -351,8 +401,7 @@ public class ShakeMenu implements ShakeDetector.Listener {
351
401
  presentChannelPicker(channels);
352
402
  });
353
403
  });
354
- })
355
- .start();
404
+ }).start();
356
405
  } catch (Exception e) {
357
406
  logger.error("Error showing channel selector: " + e.getMessage());
358
407
  isShowing = false;
@@ -543,13 +592,14 @@ public class ShakeMenu implements ShakeDetector.Listener {
543
592
  String latestKind = getString(latestRes, "kind");
544
593
  String latestMessage = getString(latestRes, "message");
545
594
 
546
- String detail = latestMessage != null && !latestMessage.isEmpty()
547
- ? latestMessage
548
- : latestError != null && !latestError.isEmpty()
549
- ? latestError
550
- : latestKind != null && !latestKind.isEmpty()
551
- ? latestKind
552
- : "server did not provide a message";
595
+ String detail =
596
+ latestMessage != null && !latestMessage.isEmpty()
597
+ ? latestMessage
598
+ : latestError != null && !latestError.isEmpty()
599
+ ? latestError
600
+ : latestKind != null && !latestKind.isEmpty()
601
+ ? latestKind
602
+ : "server did not provide a message";
553
603
 
554
604
  // Handle update errors first (before "no new version" check)
555
605
  if (
@@ -668,8 +718,7 @@ public class ShakeMenu implements ShakeDetector.Listener {
668
718
  });
669
719
  }
670
720
  );
671
- })
672
- .start();
721
+ }).start();
673
722
  } catch (Exception e) {
674
723
  logger.error("Error selecting channel: " + e.getMessage());
675
724
  isShowing = false;
package/dist/docs.json CHANGED
@@ -1431,7 +1431,7 @@
1431
1431
  "text": "7.5.0"
1432
1432
  }
1433
1433
  ],
1434
- "docs": "Enable or disable the shake gesture menu for debugging and testing.\n\nWhen enabled, users can shake their device to open a debug menu that shows:\n- Current bundle information\n- Available bundles\n- Options to switch bundles manually\n- Update status\n\nThis is useful during development and testing to:\n- Quickly test different bundle versions\n- Debug update flows\n- Switch between production and test bundles\n- Verify bundle installations\n\n**Important:** Disable this in production builds or only enable for internal testers.\n\nCan also be configured via {@link PluginsConfig.CapacitorUpdater.shakeMenu}.",
1434
+ "docs": "Enable or disable the shake gesture menu.\n\nDuring preview sessions, users can shake their device to:\n- Reload the current preview\n- Leave the test app and return to the fallback bundle\n- Switch update channel, when {@link PluginsConfig.CapacitorUpdater.allowShakeChannelSelector} is also enabled\n\nOutside preview sessions, this preview menu is ignored. The channel selector can still be\nshown outside preview sessions when {@link PluginsConfig.CapacitorUpdater.allowShakeChannelSelector} is enabled.\n\n**Important:** Disable this in production builds or only enable for internal testers.\n\nCan also be configured via {@link PluginsConfig.CapacitorUpdater.shakeMenu}.",
1435
1435
  "complexTypes": [
1436
1436
  "SetShakeMenuOptions"
1437
1437
  ],
@@ -1495,7 +1495,7 @@
1495
1495
  "text": "8.43.0"
1496
1496
  }
1497
1497
  ],
1498
- "docs": "Enable or disable the shake channel selector at runtime.\n\nWhen enabled AND shakeMenu is true, shaking the device shows a channel\nselector instead of the debug menu. This allows users to switch between\nupdate channels by shaking their device.\n\nAfter selecting a channel, the app automatically checks for updates\nand downloads if available.\n\nCan also be configured via {@link PluginsConfig.CapacitorUpdater.allowShakeChannelSelector}.",
1498
+ "docs": "Enable or disable the shake channel selector at runtime.\n\nWhen enabled, shaking the device can show a channel selector, including outside preview sessions.\nIf {@link setShakeMenu} is also enabled while a preview session is active, the shake menu includes\nboth preview actions and channel switching.\n\nCan also be configured via {@link PluginsConfig.CapacitorUpdater.allowShakeChannelSelector}.",
1499
1499
  "complexTypes": [
1500
1500
  "SetShakeChannelSelectorOptions"
1501
1501
  ],
@@ -2868,7 +2868,7 @@
2868
2868
  ],
2869
2869
  "docs": "The channel ID",
2870
2870
  "complexTypes": [],
2871
- "type": "string"
2871
+ "type": "number"
2872
2872
  },
2873
2873
  {
2874
2874
  "name": "name",
@@ -4573,7 +4573,7 @@
4573
4573
  "name": "since"
4574
4574
  }
4575
4575
  ],
4576
- "docs": "Enable shake gesture to show update menu for debugging/testing purposes",
4576
+ "docs": "Enable the shake gesture while a preview session is active.\nOutside preview sessions this preview menu is ignored, unless\n{@link PluginsConfig.CapacitorUpdater.allowShakeChannelSelector} is enabled.",
4577
4577
  "complexTypes": [],
4578
4578
  "type": "boolean | undefined"
4579
4579
  },
@@ -4589,7 +4589,7 @@
4589
4589
  "name": "since"
4590
4590
  }
4591
4591
  ],
4592
- "docs": "Enable the shake gesture to show a channel selector menu for switching between update channels.\nWhen enabled AND `shakeMenu` is true, the shake gesture shows a channel selector\ninstead of the default debug menu (Go Home/Reload/Close).\n\nAfter selecting a channel, the app automatically checks for updates and downloads if available.\nOnly works if channels have `allow_self_set` enabled on the backend.\n\nOnly available for Android and iOS.",
4592
+ "docs": "Enable the shake gesture to show a channel selector menu for switching between update channels.\nIf {@link PluginsConfig.CapacitorUpdater.shakeMenu} is also enabled while a preview session is active,\nthe shake menu includes both preview actions and channel switching.\n\nOnly available for Android and iOS.",
4593
4593
  "complexTypes": [],
4594
4594
  "type": "boolean | undefined"
4595
4595
  }
@@ -352,7 +352,9 @@ declare module '@capacitor/cli' {
352
352
  */
353
353
  osLogging?: boolean;
354
354
  /**
355
- * Enable shake gesture to show update menu for debugging/testing purposes
355
+ * Enable the shake gesture while a preview session is active.
356
+ * Outside preview sessions this preview menu is ignored, unless
357
+ * {@link PluginsConfig.CapacitorUpdater.allowShakeChannelSelector} is enabled.
356
358
  *
357
359
  * @default false
358
360
  * @since 7.5.0
@@ -360,11 +362,8 @@ declare module '@capacitor/cli' {
360
362
  shakeMenu?: boolean;
361
363
  /**
362
364
  * Enable the shake gesture to show a channel selector menu for switching between update channels.
363
- * When enabled AND `shakeMenu` is true, the shake gesture shows a channel selector
364
- * instead of the default debug menu (Go Home/Reload/Close).
365
- *
366
- * After selecting a channel, the app automatically checks for updates and downloads if available.
367
- * Only works if channels have `allow_self_set` enabled on the backend.
365
+ * If {@link PluginsConfig.CapacitorUpdater.shakeMenu} is also enabled while a preview session is active,
366
+ * the shake menu includes both preview actions and channel switching.
368
367
  *
369
368
  * Only available for Android and iOS.
370
369
  *
@@ -1257,19 +1256,15 @@ export interface CapacitorUpdaterPlugin {
1257
1256
  */
1258
1257
  getFailedUpdate(): Promise<UpdateFailedEvent | null>;
1259
1258
  /**
1260
- * Enable or disable the shake gesture menu for debugging and testing.
1259
+ * Enable or disable the shake gesture menu.
1261
1260
  *
1262
- * When enabled, users can shake their device to open a debug menu that shows:
1263
- * - Current bundle information
1264
- * - Available bundles
1265
- * - Options to switch bundles manually
1266
- * - Update status
1261
+ * During preview sessions, users can shake their device to:
1262
+ * - Reload the current preview
1263
+ * - Leave the test app and return to the fallback bundle
1264
+ * - Switch update channel, when {@link PluginsConfig.CapacitorUpdater.allowShakeChannelSelector} is also enabled
1267
1265
  *
1268
- * This is useful during development and testing to:
1269
- * - Quickly test different bundle versions
1270
- * - Debug update flows
1271
- * - Switch between production and test bundles
1272
- * - Verify bundle installations
1266
+ * Outside preview sessions, this preview menu is ignored. The channel selector can still be
1267
+ * shown outside preview sessions when {@link PluginsConfig.CapacitorUpdater.allowShakeChannelSelector} is enabled.
1273
1268
  *
1274
1269
  * **Important:** Disable this in production builds or only enable for internal testers.
1275
1270
  *
@@ -1300,12 +1295,9 @@ export interface CapacitorUpdaterPlugin {
1300
1295
  /**
1301
1296
  * Enable or disable the shake channel selector at runtime.
1302
1297
  *
1303
- * When enabled AND shakeMenu is true, shaking the device shows a channel
1304
- * selector instead of the debug menu. This allows users to switch between
1305
- * update channels by shaking their device.
1306
- *
1307
- * After selecting a channel, the app automatically checks for updates
1308
- * and downloads if available.
1298
+ * When enabled, shaking the device can show a channel selector, including outside preview sessions.
1299
+ * If {@link setShakeMenu} is also enabled while a preview session is active, the shake menu includes
1300
+ * both preview actions and channel switching.
1309
1301
  *
1310
1302
  * Can also be configured via {@link PluginsConfig.CapacitorUpdater.allowShakeChannelSelector}.
1311
1303
  *
@@ -1587,7 +1579,7 @@ export interface ChannelInfo {
1587
1579
  *
1588
1580
  * @since 7.5.0
1589
1581
  */
1590
- id: string;
1582
+ id: number;
1591
1583
  /**
1592
1584
  * The channel name
1593
1585
  *