@capgo/capacitor-updater 7.42.9 → 7.43.3

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.
@@ -10,8 +10,19 @@ import android.app.Activity;
10
10
  import android.app.AlertDialog;
11
11
  import android.content.DialogInterface;
12
12
  import android.hardware.SensorManager;
13
+ import android.text.Editable;
14
+ import android.text.TextWatcher;
15
+ import android.widget.ArrayAdapter;
16
+ import android.widget.EditText;
17
+ import android.widget.LinearLayout;
18
+ import android.widget.ListView;
19
+ import android.widget.ProgressBar;
13
20
  import com.getcapacitor.Bridge;
14
21
  import com.getcapacitor.BridgeActivity;
22
+ import java.util.ArrayList;
23
+ import java.util.List;
24
+ import java.util.Map;
25
+ import org.json.JSONArray;
15
26
 
16
27
  public class ShakeMenu implements ShakeDetector.Listener {
17
28
 
@@ -54,10 +65,16 @@ public class ShakeMenu implements ShakeDetector.Listener {
54
65
  }
55
66
 
56
67
  isShowing = true;
57
- showShakeMenu();
68
+
69
+ // Check if channel selector mode is enabled
70
+ if (plugin.shakeChannelSelectorEnabled) {
71
+ showChannelSelector();
72
+ } else {
73
+ showDefaultMenu();
74
+ }
58
75
  }
59
76
 
60
- private void showShakeMenu() {
77
+ private void showDefaultMenu() {
61
78
  activity.runOnUiThread(() -> {
62
79
  try {
63
80
  String appName = activity.getPackageManager().getApplicationLabel(activity.getApplicationInfo()).toString();
@@ -166,4 +183,421 @@ public class ShakeMenu implements ShakeDetector.Listener {
166
183
  }
167
184
  });
168
185
  }
186
+
187
+ private void showChannelSelector() {
188
+ activity.runOnUiThread(() -> {
189
+ try {
190
+ // Show loading dialog
191
+ AlertDialog.Builder loadingBuilder = new AlertDialog.Builder(activity);
192
+ loadingBuilder.setTitle("Loading Channels...");
193
+ loadingBuilder.setCancelable(true);
194
+
195
+ ProgressBar progressBar = new ProgressBar(activity);
196
+ progressBar.setIndeterminate(true);
197
+ int padding = dpToPx(20);
198
+ progressBar.setPadding(padding, padding, padding, padding);
199
+ loadingBuilder.setView(progressBar);
200
+
201
+ final boolean[] didCancel = { false };
202
+
203
+ loadingBuilder.setNegativeButton("Cancel", (dialog, which) -> {
204
+ didCancel[0] = true;
205
+ dialog.dismiss();
206
+ isShowing = false;
207
+ });
208
+
209
+ AlertDialog loadingDialog = loadingBuilder.create();
210
+ loadingDialog.setOnCancelListener((d) -> {
211
+ didCancel[0] = true;
212
+ isShowing = false;
213
+ });
214
+ loadingDialog.setOnDismissListener((d) -> {
215
+ if (didCancel[0]) {
216
+ isShowing = false;
217
+ }
218
+ });
219
+ loadingDialog.show();
220
+
221
+ // Fetch channels in background
222
+ new Thread(() -> {
223
+ final CapgoUpdater updater = plugin.implementation;
224
+ updater.listChannels((res) -> {
225
+ activity.runOnUiThread(() -> {
226
+ loadingDialog.dismiss();
227
+
228
+ if (didCancel[0]) {
229
+ return;
230
+ }
231
+
232
+ if (res == null) {
233
+ showError("Failed to load channels: unknown error");
234
+ return;
235
+ }
236
+
237
+ Object errorObj = res.get("error");
238
+ if (errorObj != null) {
239
+ Object messageObj = res.get("message");
240
+ String message = messageObj != null ? messageObj.toString() : errorObj.toString();
241
+ showError("Failed to load channels: " + message);
242
+ return;
243
+ }
244
+
245
+ Object channelsObj = res.get("channels");
246
+ if (!(channelsObj instanceof List)) {
247
+ showError("No channels available for self-assignment");
248
+ return;
249
+ }
250
+
251
+ List<?> channelsRaw = (List<?>) channelsObj;
252
+ List<Map<String, Object>> channels = new ArrayList<>();
253
+ for (Object item : channelsRaw) {
254
+ if (item instanceof Map) {
255
+ channels.add((Map<String, Object>) item);
256
+ }
257
+ }
258
+
259
+ if (channels.isEmpty()) {
260
+ showError("No channels available for self-assignment");
261
+ return;
262
+ }
263
+
264
+ presentChannelPicker(channels);
265
+ });
266
+ });
267
+ })
268
+ .start();
269
+ } catch (Exception e) {
270
+ logger.error("Error showing channel selector: " + e.getMessage());
271
+ isShowing = false;
272
+ }
273
+ });
274
+ }
275
+
276
+ private void presentChannelPicker(List<Map<String, Object>> channels) {
277
+ try {
278
+ AlertDialog.Builder builder = new AlertDialog.Builder(activity);
279
+ builder.setTitle("Select Channel");
280
+
281
+ // Create custom layout with search and channel list
282
+ LinearLayout layout = new LinearLayout(activity);
283
+ layout.setOrientation(LinearLayout.VERTICAL);
284
+ int padding = dpToPx(16);
285
+ layout.setPadding(padding, padding, padding, padding);
286
+
287
+ // Search field
288
+ EditText searchField = new EditText(activity);
289
+ searchField.setHint("Search channels...");
290
+ searchField.setSingleLine(true);
291
+ layout.addView(searchField);
292
+
293
+ // Create list of channel names
294
+ List<String> allChannelNames = new ArrayList<>();
295
+ for (Map<String, Object> channel : channels) {
296
+ Object nameObj = channel.get("name");
297
+ if (nameObj instanceof String) {
298
+ allChannelNames.add((String) nameObj);
299
+ }
300
+ }
301
+
302
+ // Displayed channels (first 5 by default)
303
+ final List<String> displayedChannels = new ArrayList<>();
304
+ displayedChannels.addAll(allChannelNames.subList(0, Math.min(5, allChannelNames.size())));
305
+
306
+ final ArrayAdapter<String> adapter = new ArrayAdapter<>(activity, android.R.layout.simple_list_item_1, displayedChannels);
307
+
308
+ ListView listView = new ListView(activity);
309
+ listView.setAdapter(adapter);
310
+
311
+ // Set fixed height for list (about 5 items)
312
+ LinearLayout.LayoutParams listParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, dpToPx(250));
313
+ listView.setLayoutParams(listParams);
314
+ layout.addView(listView);
315
+
316
+ builder.setView(layout);
317
+ builder.setNegativeButton("Cancel", (dialog, which) -> {
318
+ dialog.dismiss();
319
+ isShowing = false;
320
+ });
321
+
322
+ AlertDialog dialog = builder.create();
323
+ dialog.setOnDismissListener((d) -> isShowing = false);
324
+
325
+ // Search filter
326
+ searchField.addTextChangedListener(
327
+ new TextWatcher() {
328
+ @Override
329
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
330
+
331
+ @Override
332
+ public void onTextChanged(CharSequence s, int start, int before, int count) {}
333
+
334
+ @Override
335
+ public void afterTextChanged(Editable s) {
336
+ String query = s.toString().toLowerCase();
337
+ displayedChannels.clear();
338
+
339
+ int count = 0;
340
+ for (String name : allChannelNames) {
341
+ if (name.toLowerCase().contains(query)) {
342
+ displayedChannels.add(name);
343
+ count++;
344
+ if (count >= 5) break;
345
+ }
346
+ }
347
+
348
+ adapter.notifyDataSetChanged();
349
+ }
350
+ }
351
+ );
352
+
353
+ // Channel selection
354
+ listView.setOnItemClickListener((parent, view, position, id) -> {
355
+ String selectedChannel = displayedChannels.get(position);
356
+ dialog.dismiss();
357
+ selectChannel(selectedChannel);
358
+ });
359
+
360
+ dialog.show();
361
+ } catch (Exception e) {
362
+ logger.error("Error presenting channel picker: " + e.getMessage());
363
+ isShowing = false;
364
+ }
365
+ }
366
+
367
+ private void selectChannel(String channelName) {
368
+ activity.runOnUiThread(() -> {
369
+ try {
370
+ // Show progress dialog
371
+ AlertDialog.Builder progressBuilder = new AlertDialog.Builder(activity);
372
+ progressBuilder.setTitle("Switching to " + channelName);
373
+ progressBuilder.setMessage("Setting channel...");
374
+ progressBuilder.setCancelable(false);
375
+
376
+ ProgressBar progressBar = new ProgressBar(activity);
377
+ progressBar.setIndeterminate(true);
378
+ int padding = dpToPx(20);
379
+ progressBar.setPadding(padding, padding, padding, padding);
380
+ progressBuilder.setView(progressBar);
381
+
382
+ AlertDialog progressDialog = progressBuilder.create();
383
+ progressDialog.show();
384
+
385
+ new Thread(() -> {
386
+ final CapgoUpdater updater = plugin.implementation;
387
+ final Bridge bridge = activity.getBridge();
388
+
389
+ // Set the channel - respect plugin's allowSetDefaultChannel config
390
+ updater.setChannel(
391
+ channelName,
392
+ updater.editor,
393
+ "CapacitorUpdater.defaultChannel",
394
+ plugin.allowSetDefaultChannel,
395
+ (setRes) -> {
396
+ if (setRes == null) {
397
+ activity.runOnUiThread(() -> {
398
+ progressDialog.dismiss();
399
+ showError("Failed to set channel: unknown error");
400
+ });
401
+ return;
402
+ }
403
+
404
+ Object errorObj = setRes.get("error");
405
+ if (errorObj != null) {
406
+ Object messageObj = setRes.get("message");
407
+ String message = messageObj != null ? messageObj.toString() : errorObj.toString();
408
+ activity.runOnUiThread(() -> {
409
+ progressDialog.dismiss();
410
+ showError("Failed to set channel: " + message);
411
+ });
412
+ return;
413
+ }
414
+
415
+ // Update progress message
416
+ activity.runOnUiThread(() -> progressDialog.setMessage("Checking for updates..."));
417
+
418
+ // Check for updates
419
+ String updateUrlStr = plugin.getUpdateUrl();
420
+ if (updateUrlStr == null || updateUrlStr.isEmpty()) {
421
+ updateUrlStr = "https://plugin.capgo.app/updates";
422
+ }
423
+
424
+ final String finalUpdateUrlStr = updateUrlStr;
425
+ updater.getLatest(finalUpdateUrlStr, channelName, (latestRes) -> {
426
+ if (latestRes == null) {
427
+ activity.runOnUiThread(() -> {
428
+ progressDialog.dismiss();
429
+ showSuccess("Channel set to " + channelName + ". Could not check for updates.");
430
+ });
431
+ return;
432
+ }
433
+
434
+ String latestError = getString(latestRes, "error");
435
+
436
+ // Handle update errors first (before "no new version" check)
437
+ if (latestError != null && !latestError.isEmpty() && !"no_new_version_available".equals(latestError)) {
438
+ activity.runOnUiThread(() -> {
439
+ progressDialog.dismiss();
440
+ showError("Channel set to " + channelName + ". Update check failed: " + latestError);
441
+ });
442
+ return;
443
+ }
444
+
445
+ String latestUrl = getString(latestRes, "url");
446
+
447
+ // Check if there's an actual update available
448
+ if ("no_new_version_available".equals(latestError) || latestUrl == null || latestUrl.isEmpty()) {
449
+ activity.runOnUiThread(() -> {
450
+ progressDialog.dismiss();
451
+ showSuccess("Channel set to " + channelName + ". Already on latest version.");
452
+ });
453
+ return;
454
+ }
455
+
456
+ String version = getString(latestRes, "version");
457
+ if (version == null || version.isEmpty()) {
458
+ activity.runOnUiThread(() -> {
459
+ progressDialog.dismiss();
460
+ showError("Channel set to " + channelName + ". Update check failed: missing version.");
461
+ });
462
+ return;
463
+ }
464
+
465
+ // Update message
466
+ final String versionForUi = version;
467
+ activity.runOnUiThread(() -> progressDialog.setMessage("Downloading update " + versionForUi + "..."));
468
+
469
+ String sessionKey = getString(latestRes, "sessionKey");
470
+ String checksum = getString(latestRes, "checksum");
471
+ Object manifestObj = latestRes.get("manifest");
472
+
473
+ // Download the update
474
+ try {
475
+ BundleInfo bundle;
476
+ if (manifestObj != null) {
477
+ JSONArray manifestArray = null;
478
+ if (manifestObj instanceof JSONArray) {
479
+ manifestArray = (JSONArray) manifestObj;
480
+ } else if (manifestObj instanceof List) {
481
+ manifestArray = new JSONArray((List<?>) manifestObj);
482
+ }
483
+
484
+ if (manifestArray == null) {
485
+ throw new IllegalArgumentException("Invalid manifest format");
486
+ }
487
+
488
+ bundle = updater.downloadManifest(
489
+ latestUrl,
490
+ versionForUi,
491
+ sessionKey != null ? sessionKey : "",
492
+ checksum != null ? checksum : "",
493
+ manifestArray
494
+ );
495
+ } else {
496
+ bundle = updater.download(
497
+ latestUrl,
498
+ versionForUi,
499
+ sessionKey != null ? sessionKey : "",
500
+ checksum != null ? checksum : ""
501
+ );
502
+ }
503
+
504
+ // Set as next bundle
505
+ updater.setNextBundle(bundle.getId());
506
+
507
+ activity.runOnUiThread(() -> {
508
+ progressDialog.dismiss();
509
+ showSuccessWithReload("Update downloaded! Reload to apply version " + versionForUi + "?", () -> {
510
+ try {
511
+ if (bridge == null) {
512
+ logger.warn("Bridge is null, cannot reload app");
513
+ return;
514
+ }
515
+ updater.set(bundle);
516
+ String path = updater.getCurrentBundlePath();
517
+ if (updater.isUsingBuiltin()) {
518
+ bridge.setServerAssetPath(path);
519
+ } else {
520
+ bridge.setServerBasePath(path);
521
+ }
522
+ if (bridge.getWebView() != null) {
523
+ bridge.getWebView().reload();
524
+ }
525
+ } catch (Exception e) {
526
+ logger.error("Error applying bundle before reload: " + e.getMessage());
527
+ }
528
+ });
529
+ });
530
+ } catch (Exception e) {
531
+ activity.runOnUiThread(() -> {
532
+ progressDialog.dismiss();
533
+ showError("Failed to download update: " + e.getMessage());
534
+ });
535
+ }
536
+ });
537
+ }
538
+ );
539
+ })
540
+ .start();
541
+ } catch (Exception e) {
542
+ logger.error("Error selecting channel: " + e.getMessage());
543
+ isShowing = false;
544
+ }
545
+ });
546
+ }
547
+
548
+ private void showError(String message) {
549
+ logger.error(message);
550
+ new AlertDialog.Builder(activity)
551
+ .setTitle("Error")
552
+ .setMessage(message)
553
+ .setPositiveButton("OK", (d, w) -> {
554
+ d.dismiss();
555
+ isShowing = false;
556
+ })
557
+ .setOnDismissListener((d) -> isShowing = false)
558
+ .show();
559
+ }
560
+
561
+ private void showSuccess(String message) {
562
+ logger.info(message);
563
+ new AlertDialog.Builder(activity)
564
+ .setTitle("Success")
565
+ .setMessage(message)
566
+ .setPositiveButton("OK", (d, w) -> {
567
+ d.dismiss();
568
+ isShowing = false;
569
+ })
570
+ .setOnDismissListener((d) -> isShowing = false)
571
+ .show();
572
+ }
573
+
574
+ private void showSuccessWithReload(String message, Runnable onReload) {
575
+ logger.info(message);
576
+ new AlertDialog.Builder(activity)
577
+ .setTitle("Update Ready")
578
+ .setMessage(message)
579
+ .setPositiveButton("Reload Now", (d, w) -> {
580
+ d.dismiss();
581
+ isShowing = false;
582
+ if (onReload != null) {
583
+ onReload.run();
584
+ }
585
+ })
586
+ .setNegativeButton("Later", (d, w) -> {
587
+ d.dismiss();
588
+ isShowing = false;
589
+ })
590
+ .setOnDismissListener((d) -> isShowing = false)
591
+ .show();
592
+ }
593
+
594
+ private String getString(Map<String, Object> map, String key) {
595
+ Object value = map.get(key);
596
+ return value != null ? value.toString() : null;
597
+ }
598
+
599
+ private int dpToPx(int dp) {
600
+ float density = activity.getResources().getDisplayMetrics().density;
601
+ return Math.round(dp * density);
602
+ }
169
603
  }
package/dist/docs.json CHANGED
@@ -1255,6 +1255,70 @@
1255
1255
  ],
1256
1256
  "slug": "isshakemenuenabled"
1257
1257
  },
1258
+ {
1259
+ "name": "setShakeChannelSelector",
1260
+ "signature": "(options: SetShakeChannelSelectorOptions) => Promise<void>",
1261
+ "parameters": [
1262
+ {
1263
+ "name": "options",
1264
+ "docs": "",
1265
+ "type": "SetShakeChannelSelectorOptions"
1266
+ }
1267
+ ],
1268
+ "returns": "Promise<void>",
1269
+ "tags": [
1270
+ {
1271
+ "name": "param",
1272
+ "text": "options"
1273
+ },
1274
+ {
1275
+ "name": "link",
1276
+ "text": "SetShakeChannelSelectorOptions} with `enabled: true` to enable or `enabled: false` to disable."
1277
+ },
1278
+ {
1279
+ "name": "returns",
1280
+ "text": "Resolves when the setting is applied."
1281
+ },
1282
+ {
1283
+ "name": "throws",
1284
+ "text": "{Error} If the operation fails."
1285
+ },
1286
+ {
1287
+ "name": "since",
1288
+ "text": "8.43.0"
1289
+ }
1290
+ ],
1291
+ "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}.",
1292
+ "complexTypes": [
1293
+ "SetShakeChannelSelectorOptions"
1294
+ ],
1295
+ "slug": "setshakechannelselector"
1296
+ },
1297
+ {
1298
+ "name": "isShakeChannelSelectorEnabled",
1299
+ "signature": "() => Promise<ShakeChannelSelectorEnabled>",
1300
+ "parameters": [],
1301
+ "returns": "Promise<ShakeChannelSelectorEnabled>",
1302
+ "tags": [
1303
+ {
1304
+ "name": "returns",
1305
+ "text": "Object with `enabled: true` or `enabled: false`."
1306
+ },
1307
+ {
1308
+ "name": "throws",
1309
+ "text": "{Error} If the operation fails."
1310
+ },
1311
+ {
1312
+ "name": "since",
1313
+ "text": "8.43.0"
1314
+ }
1315
+ ],
1316
+ "docs": "Check if the shake channel selector is currently enabled.\n\nReturns the current state of the shake channel selector feature that can be toggled via\n{@link setShakeChannelSelector} or configured via {@link PluginsConfig.CapacitorUpdater.allowShakeChannelSelector}.",
1317
+ "complexTypes": [
1318
+ "ShakeChannelSelectorEnabled"
1319
+ ],
1320
+ "slug": "isshakechannelselectorenabled"
1321
+ },
1258
1322
  {
1259
1323
  "name": "getAppId",
1260
1324
  "signature": "() => Promise<GetAppIdRes>",
@@ -2614,6 +2678,38 @@
2614
2678
  }
2615
2679
  ]
2616
2680
  },
2681
+ {
2682
+ "name": "SetShakeChannelSelectorOptions",
2683
+ "slug": "setshakechannelselectoroptions",
2684
+ "docs": "",
2685
+ "tags": [],
2686
+ "methods": [],
2687
+ "properties": [
2688
+ {
2689
+ "name": "enabled",
2690
+ "tags": [],
2691
+ "docs": "",
2692
+ "complexTypes": [],
2693
+ "type": "boolean"
2694
+ }
2695
+ ]
2696
+ },
2697
+ {
2698
+ "name": "ShakeChannelSelectorEnabled",
2699
+ "slug": "shakechannelselectorenabled",
2700
+ "docs": "",
2701
+ "tags": [],
2702
+ "methods": [],
2703
+ "properties": [
2704
+ {
2705
+ "name": "enabled",
2706
+ "tags": [],
2707
+ "docs": "",
2708
+ "complexTypes": [],
2709
+ "type": "boolean"
2710
+ }
2711
+ ]
2712
+ },
2617
2713
  {
2618
2714
  "name": "GetAppIdRes",
2619
2715
  "slug": "getappidres",
@@ -3658,6 +3754,22 @@
3658
3754
  "docs": "Enable shake gesture to show update menu for debugging/testing purposes",
3659
3755
  "complexTypes": [],
3660
3756
  "type": "boolean | undefined"
3757
+ },
3758
+ {
3759
+ "name": "allowShakeChannelSelector",
3760
+ "tags": [
3761
+ {
3762
+ "text": "false",
3763
+ "name": "default"
3764
+ },
3765
+ {
3766
+ "text": "8.43.0",
3767
+ "name": "since"
3768
+ }
3769
+ ],
3770
+ "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.",
3771
+ "complexTypes": [],
3772
+ "type": "boolean | undefined"
3661
3773
  }
3662
3774
  ],
3663
3775
  "docs": "CapacitorUpdater can be configured with these options:"
@@ -330,6 +330,20 @@ declare module '@capacitor/cli' {
330
330
  * @since 7.5.0
331
331
  */
332
332
  shakeMenu?: boolean;
333
+ /**
334
+ * Enable the shake gesture to show a channel selector menu for switching between update channels.
335
+ * When enabled AND `shakeMenu` is true, the shake gesture shows a channel selector
336
+ * instead of the default debug menu (Go Home/Reload/Close).
337
+ *
338
+ * After selecting a channel, the app automatically checks for updates and downloads if available.
339
+ * Only works if channels have `allow_self_set` enabled on the backend.
340
+ *
341
+ * Only available for Android and iOS.
342
+ *
343
+ * @default false
344
+ * @since 8.43.0
345
+ */
346
+ allowShakeChannelSelector?: boolean;
333
347
  };
334
348
  }
335
349
  }
@@ -1143,6 +1157,35 @@ export interface CapacitorUpdaterPlugin {
1143
1157
  * @since 7.5.0
1144
1158
  */
1145
1159
  isShakeMenuEnabled(): Promise<ShakeMenuEnabled>;
1160
+ /**
1161
+ * Enable or disable the shake channel selector at runtime.
1162
+ *
1163
+ * When enabled AND shakeMenu is true, shaking the device shows a channel
1164
+ * selector instead of the debug menu. This allows users to switch between
1165
+ * update channels by shaking their device.
1166
+ *
1167
+ * After selecting a channel, the app automatically checks for updates
1168
+ * and downloads if available.
1169
+ *
1170
+ * Can also be configured via {@link PluginsConfig.CapacitorUpdater.allowShakeChannelSelector}.
1171
+ *
1172
+ * @param options {@link SetShakeChannelSelectorOptions} with `enabled: true` to enable or `enabled: false` to disable.
1173
+ * @returns {Promise<void>} Resolves when the setting is applied.
1174
+ * @throws {Error} If the operation fails.
1175
+ * @since 8.43.0
1176
+ */
1177
+ setShakeChannelSelector(options: SetShakeChannelSelectorOptions): Promise<void>;
1178
+ /**
1179
+ * Check if the shake channel selector is currently enabled.
1180
+ *
1181
+ * Returns the current state of the shake channel selector feature that can be toggled via
1182
+ * {@link setShakeChannelSelector} or configured via {@link PluginsConfig.CapacitorUpdater.allowShakeChannelSelector}.
1183
+ *
1184
+ * @returns {Promise<ShakeChannelSelectorEnabled>} Object with `enabled: true` or `enabled: false`.
1185
+ * @throws {Error} If the operation fails.
1186
+ * @since 8.43.0
1187
+ */
1188
+ isShakeChannelSelectorEnabled(): Promise<ShakeChannelSelectorEnabled>;
1146
1189
  /**
1147
1190
  * Get the currently configured App ID used for update server communication.
1148
1191
  *
@@ -1641,6 +1684,12 @@ export interface SetShakeMenuOptions {
1641
1684
  export interface ShakeMenuEnabled {
1642
1685
  enabled: boolean;
1643
1686
  }
1687
+ export interface SetShakeChannelSelectorOptions {
1688
+ enabled: boolean;
1689
+ }
1690
+ export interface ShakeChannelSelectorEnabled {
1691
+ enabled: boolean;
1692
+ }
1644
1693
  export interface GetAppIdRes {
1645
1694
  appId: string;
1646
1695
  }