@capgo/capacitor-updater 7.4.0 → 7.6.0

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.
@@ -35,6 +35,7 @@ import java.util.Objects;
35
35
  import java.util.zip.ZipEntry;
36
36
  import java.util.zip.ZipInputStream;
37
37
  import okhttp3.*;
38
+ import okhttp3.HttpUrl;
38
39
  import org.json.JSONArray;
39
40
  import org.json.JSONException;
40
41
  import org.json.JSONObject;
@@ -699,6 +700,16 @@ public class CapgoUpdater {
699
700
  assert responseBody != null;
700
701
  String responseData = responseBody.string();
701
702
  JSONObject jsonResponse = new JSONObject(responseData);
703
+
704
+ // Check for server-side errors first
705
+ if (jsonResponse.has("error")) {
706
+ Map<String, Object> retError = new HashMap<>();
707
+ retError.put("message", jsonResponse.getString("error"));
708
+ retError.put("error", "server_error");
709
+ callback.callback(retError);
710
+ return;
711
+ }
712
+
702
713
  Map<String, Object> ret = new HashMap<>();
703
714
 
704
715
  Iterator<String> keys = jsonResponse.keys();
@@ -798,6 +809,16 @@ public class CapgoUpdater {
798
809
  assert responseBody != null;
799
810
  String responseData = responseBody.string();
800
811
  JSONObject jsonResponse = new JSONObject(responseData);
812
+
813
+ // Check for server-side errors first
814
+ if (jsonResponse.has("error")) {
815
+ Map<String, Object> retError = new HashMap<>();
816
+ retError.put("message", jsonResponse.getString("error"));
817
+ retError.put("error", "server_error");
818
+ callback.callback(retError);
819
+ return;
820
+ }
821
+
801
822
  Map<String, Object> ret = new HashMap<>();
802
823
 
803
824
  Iterator<String> keys = jsonResponse.keys();
@@ -912,6 +933,16 @@ public class CapgoUpdater {
912
933
  assert responseBody != null;
913
934
  String responseData = responseBody.string();
914
935
  JSONObject jsonResponse = new JSONObject(responseData);
936
+
937
+ // Check for server-side errors first
938
+ if (jsonResponse.has("error")) {
939
+ Map<String, Object> retError = new HashMap<>();
940
+ retError.put("message", jsonResponse.getString("error"));
941
+ retError.put("error", "server_error");
942
+ callback.callback(retError);
943
+ return;
944
+ }
945
+
915
946
  Map<String, Object> ret = new HashMap<>();
916
947
 
917
948
  Iterator<String> keys = jsonResponse.keys();
@@ -934,6 +965,109 @@ public class CapgoUpdater {
934
965
  );
935
966
  }
936
967
 
968
+ public void listChannels(final Callback callback) {
969
+ String channelUrl = this.channelUrl;
970
+ if (channelUrl == null || channelUrl.isEmpty()) {
971
+ logger.error("Channel URL is not set");
972
+ final Map<String, Object> retError = new HashMap<>();
973
+ retError.put("message", "Channel URL is not set");
974
+ retError.put("error", "missing_config");
975
+ callback.callback(retError);
976
+ return;
977
+ }
978
+
979
+ // Auto-detect values
980
+ String appId = this.appId;
981
+ String platform = "android";
982
+ boolean isEmulator = this.isEmulator();
983
+ boolean isProd = this.isProd();
984
+
985
+ // Build URL with query parameters
986
+ HttpUrl.Builder urlBuilder = HttpUrl.parse(channelUrl).newBuilder();
987
+ urlBuilder.addQueryParameter("app_id", appId);
988
+ urlBuilder.addQueryParameter("platform", platform);
989
+ urlBuilder.addQueryParameter("is_emulator", String.valueOf(isEmulator));
990
+ urlBuilder.addQueryParameter("is_prod", String.valueOf(isProd));
991
+
992
+ Request request = new Request.Builder().url(urlBuilder.build()).get().build();
993
+
994
+ client
995
+ .newCall(request)
996
+ .enqueue(
997
+ new okhttp3.Callback() {
998
+ @Override
999
+ public void onFailure(@NonNull Call call, @NonNull IOException e) {
1000
+ Map<String, Object> retError = new HashMap<>();
1001
+ retError.put("message", "Request failed: " + e.getMessage());
1002
+ retError.put("error", "network_error");
1003
+ callback.callback(retError);
1004
+ }
1005
+
1006
+ @Override
1007
+ public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
1008
+ try (ResponseBody responseBody = response.body()) {
1009
+ if (!response.isSuccessful()) {
1010
+ Map<String, Object> retError = new HashMap<>();
1011
+ retError.put("message", "Server error: " + response.code());
1012
+ retError.put("error", "response_error");
1013
+ callback.callback(retError);
1014
+ return;
1015
+ }
1016
+
1017
+ assert responseBody != null;
1018
+ String data = responseBody.string();
1019
+
1020
+ try {
1021
+ Map<String, Object> ret = new HashMap<>();
1022
+
1023
+ try {
1024
+ // Try to parse as direct array first
1025
+ JSONArray channelsJson = new JSONArray(data);
1026
+ List<Map<String, Object>> channelsList = new ArrayList<>();
1027
+
1028
+ for (int i = 0; i < channelsJson.length(); i++) {
1029
+ JSONObject channelJson = channelsJson.getJSONObject(i);
1030
+ Map<String, Object> channel = new HashMap<>();
1031
+ channel.put("id", channelJson.optString("id", ""));
1032
+ channel.put("name", channelJson.optString("name", ""));
1033
+ channel.put("public", channelJson.optBoolean("public", false));
1034
+ channel.put("allow_self_set", channelJson.optBoolean("allow_self_set", false));
1035
+ channelsList.add(channel);
1036
+ }
1037
+
1038
+ // Wrap in channels object for JS API
1039
+ ret.put("channels", channelsList);
1040
+
1041
+ logger.info("Channels listed successfully");
1042
+ callback.callback(ret);
1043
+ } catch (JSONException arrayException) {
1044
+ // If not an array, try to parse as error object
1045
+ try {
1046
+ JSONObject json = new JSONObject(data);
1047
+ if (json.has("error")) {
1048
+ Map<String, Object> retError = new HashMap<>();
1049
+ retError.put("message", json.getString("error"));
1050
+ retError.put("error", "server_error");
1051
+ callback.callback(retError);
1052
+ return;
1053
+ }
1054
+ } catch (JSONException objException) {
1055
+ // If neither array nor object, throw parse error
1056
+ throw arrayException;
1057
+ }
1058
+ }
1059
+ } catch (JSONException e) {
1060
+ Map<String, Object> retError = new HashMap<>();
1061
+ retError.put("message", "JSON parse error: " + e.getMessage());
1062
+ retError.put("error", "parse_error");
1063
+ callback.callback(retError);
1064
+ }
1065
+ }
1066
+ }
1067
+ }
1068
+ );
1069
+ }
1070
+
937
1071
  public void sendStats(final String action) {
938
1072
  this.sendStats(action, this.getCurrentBundle().getVersionName());
939
1073
  }
@@ -0,0 +1,72 @@
1
+ /*
2
+ * This Source Code Form is subject to the terms of the Mozilla Public
3
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
4
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
5
+ */
6
+
7
+ package ee.forgr.capacitor_updater;
8
+
9
+ import android.hardware.Sensor;
10
+ import android.hardware.SensorEvent;
11
+ import android.hardware.SensorEventListener;
12
+ import android.hardware.SensorManager;
13
+
14
+ public class ShakeDetector implements SensorEventListener {
15
+
16
+ public interface Listener {
17
+ void onShakeDetected();
18
+ }
19
+
20
+ private static final float SHAKE_THRESHOLD = 12.0f; // Acceleration threshold for shake detection
21
+ private static final int SHAKE_TIMEOUT = 500; // Minimum time between shake events (ms)
22
+
23
+ private Listener listener;
24
+ private SensorManager sensorManager;
25
+ private Sensor accelerometer;
26
+ private long lastShakeTime = 0;
27
+
28
+ public ShakeDetector(Listener listener) {
29
+ this.listener = listener;
30
+ }
31
+
32
+ public void start(SensorManager sensorManager) {
33
+ this.sensorManager = sensorManager;
34
+ this.accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
35
+
36
+ if (accelerometer != null) {
37
+ sensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_GAME);
38
+ }
39
+ }
40
+
41
+ public void stop() {
42
+ if (sensorManager != null) {
43
+ sensorManager.unregisterListener(this);
44
+ }
45
+ }
46
+
47
+ @Override
48
+ public void onSensorChanged(SensorEvent event) {
49
+ if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
50
+ float x = event.values[0];
51
+ float y = event.values[1];
52
+ float z = event.values[2];
53
+
54
+ // Calculate the acceleration magnitude (excluding gravity)
55
+ float acceleration = (float) Math.sqrt(x * x + y * y + z * z) - SensorManager.GRAVITY_EARTH;
56
+
57
+ // Check if acceleration exceeds threshold and enough time has passed
58
+ long currentTime = System.currentTimeMillis();
59
+ if (Math.abs(acceleration) > SHAKE_THRESHOLD && currentTime - lastShakeTime > SHAKE_TIMEOUT) {
60
+ lastShakeTime = currentTime;
61
+ if (listener != null) {
62
+ listener.onShakeDetected();
63
+ }
64
+ }
65
+ }
66
+ }
67
+
68
+ @Override
69
+ public void onAccuracyChanged(Sensor sensor, int accuracy) {
70
+ // Not needed for shake detection
71
+ }
72
+ }
@@ -0,0 +1,169 @@
1
+ /*
2
+ * This Source Code Form is subject to the terms of the Mozilla Public
3
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
4
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
5
+ */
6
+
7
+ package ee.forgr.capacitor_updater;
8
+
9
+ import android.app.Activity;
10
+ import android.app.AlertDialog;
11
+ import android.content.DialogInterface;
12
+ import android.hardware.SensorManager;
13
+ import com.getcapacitor.Bridge;
14
+ import com.getcapacitor.BridgeActivity;
15
+
16
+ public class ShakeMenu implements ShakeDetector.Listener {
17
+
18
+ private CapacitorUpdaterPlugin plugin;
19
+ private BridgeActivity activity;
20
+ private ShakeDetector shakeDetector;
21
+ private boolean isShowing = false;
22
+ private Logger logger;
23
+
24
+ public ShakeMenu(CapacitorUpdaterPlugin plugin, BridgeActivity activity, Logger logger) {
25
+ this.plugin = plugin;
26
+ this.activity = activity;
27
+ this.logger = logger;
28
+
29
+ SensorManager sensorManager = (SensorManager) activity.getSystemService(Activity.SENSOR_SERVICE);
30
+ this.shakeDetector = new ShakeDetector(this);
31
+ this.shakeDetector.start(sensorManager);
32
+ }
33
+
34
+ public void stop() {
35
+ if (shakeDetector != null) {
36
+ shakeDetector.stop();
37
+ }
38
+ }
39
+
40
+ @Override
41
+ public void onShakeDetected() {
42
+ logger.info("Shake detected");
43
+
44
+ // Check if shake menu is enabled
45
+ if (!plugin.shakeMenuEnabled) {
46
+ logger.info("Shake menu is disabled");
47
+ return;
48
+ }
49
+
50
+ // Prevent multiple dialogs
51
+ if (isShowing) {
52
+ logger.info("Dialog already showing");
53
+ return;
54
+ }
55
+
56
+ isShowing = true;
57
+ showShakeMenu();
58
+ }
59
+
60
+ private void showShakeMenu() {
61
+ activity.runOnUiThread(() -> {
62
+ try {
63
+ String appName = activity.getPackageManager().getApplicationLabel(activity.getApplicationInfo()).toString();
64
+ String title = "Preview " + appName + " Menu";
65
+ String message = "What would you like to do?";
66
+ String okButtonTitle = "Go Home";
67
+ String reloadButtonTitle = "Reload app";
68
+ String cancelButtonTitle = "Close menu";
69
+
70
+ CapgoUpdater updater = plugin.implementation;
71
+ Bridge bridge = activity.getBridge();
72
+
73
+ AlertDialog.Builder builder = new AlertDialog.Builder(activity);
74
+ builder.setTitle(title);
75
+ builder.setMessage(message);
76
+
77
+ // Go Home button
78
+ builder.setPositiveButton(
79
+ okButtonTitle,
80
+ new DialogInterface.OnClickListener() {
81
+ public void onClick(DialogInterface dialog, int id) {
82
+ try {
83
+ BundleInfo current = updater.getCurrentBundle();
84
+ logger.info("Current bundle: " + current.toString());
85
+
86
+ BundleInfo next = updater.getNextBundle();
87
+ logger.info("Next bundle: " + (next != null ? next.toString() : "null"));
88
+
89
+ if (next != null && !next.isBuiltin()) {
90
+ logger.info("Setting bundle to: " + next.toString());
91
+ updater.set(next);
92
+ String path = updater.getCurrentBundlePath();
93
+ logger.info("Setting server path: " + path);
94
+ if (updater.isUsingBuiltin()) {
95
+ bridge.setServerAssetPath(path);
96
+ } else {
97
+ bridge.setServerBasePath(path);
98
+ }
99
+ } else {
100
+ logger.info("Resetting to builtin");
101
+ updater.reset();
102
+ String path = updater.getCurrentBundlePath();
103
+ bridge.setServerAssetPath(path);
104
+ }
105
+
106
+ // Try to delete the current bundle
107
+ try {
108
+ updater.delete(current.getId());
109
+ } catch (Exception err) {
110
+ logger.warn("Cannot delete version " + current.getId() + ": " + err.getMessage());
111
+ }
112
+
113
+ logger.info("Reload app done");
114
+ } catch (Exception e) {
115
+ logger.error("Error in Go Home action: " + e.getMessage());
116
+ } finally {
117
+ dialog.dismiss();
118
+ isShowing = false;
119
+ }
120
+ }
121
+ }
122
+ );
123
+
124
+ // Reload button
125
+ builder.setNeutralButton(
126
+ reloadButtonTitle,
127
+ new DialogInterface.OnClickListener() {
128
+ public void onClick(DialogInterface dialog, int id) {
129
+ try {
130
+ logger.info("Reloading webview");
131
+ String pathHot = updater.getCurrentBundlePath();
132
+ bridge.setServerBasePath(pathHot);
133
+ activity.runOnUiThread(() -> {
134
+ if (bridge.getWebView() != null) {
135
+ bridge.getWebView().reload();
136
+ }
137
+ });
138
+ } catch (Exception e) {
139
+ logger.error("Error in Reload action: " + e.getMessage());
140
+ } finally {
141
+ dialog.dismiss();
142
+ isShowing = false;
143
+ }
144
+ }
145
+ }
146
+ );
147
+
148
+ // Cancel button
149
+ builder.setNegativeButton(
150
+ cancelButtonTitle,
151
+ new DialogInterface.OnClickListener() {
152
+ public void onClick(DialogInterface dialog, int id) {
153
+ logger.info("Shake menu cancelled");
154
+ dialog.dismiss();
155
+ isShowing = false;
156
+ }
157
+ }
158
+ );
159
+
160
+ AlertDialog dialog = builder.create();
161
+ dialog.setOnDismissListener(dialogInterface -> isShowing = false);
162
+ dialog.show();
163
+ } catch (Exception e) {
164
+ logger.error("Error showing shake menu: " + e.getMessage());
165
+ isShowing = false;
166
+ }
167
+ });
168
+ }
169
+ }
package/dist/docs.json CHANGED
@@ -547,6 +547,31 @@
547
547
  ],
548
548
  "slug": "getchannel"
549
549
  },
550
+ {
551
+ "name": "listChannels",
552
+ "signature": "() => Promise<ListChannelsResult>",
553
+ "parameters": [],
554
+ "returns": "Promise<ListChannelsResult>",
555
+ "tags": [
556
+ {
557
+ "name": "returns",
558
+ "text": "A Promise that resolves with the available channels"
559
+ },
560
+ {
561
+ "name": "throws",
562
+ "text": "{Error}"
563
+ },
564
+ {
565
+ "name": "since",
566
+ "text": "7.5.0"
567
+ }
568
+ ],
569
+ "docs": "List all channels available for this device that allow self-assignment",
570
+ "complexTypes": [
571
+ "ListChannelsResult"
572
+ ],
573
+ "slug": "listchannels"
574
+ },
550
575
  {
551
576
  "name": "setCustomId",
552
577
  "signature": "(options: SetCustomIdOptions) => Promise<void>",
@@ -986,6 +1011,65 @@
986
1011
  "BundleInfo"
987
1012
  ],
988
1013
  "slug": "getnextbundle"
1014
+ },
1015
+ {
1016
+ "name": "setShakeMenu",
1017
+ "signature": "(options: SetShakeMenuOptions) => Promise<void>",
1018
+ "parameters": [
1019
+ {
1020
+ "name": "options",
1021
+ "docs": "Contains enabled boolean to enable or disable shake menu",
1022
+ "type": "SetShakeMenuOptions"
1023
+ }
1024
+ ],
1025
+ "returns": "Promise<void>",
1026
+ "tags": [
1027
+ {
1028
+ "name": "param",
1029
+ "text": "options Contains enabled boolean to enable or disable shake menu"
1030
+ },
1031
+ {
1032
+ "name": "returns"
1033
+ },
1034
+ {
1035
+ "name": "throws",
1036
+ "text": "{Error}"
1037
+ },
1038
+ {
1039
+ "name": "since",
1040
+ "text": "7.5.0"
1041
+ }
1042
+ ],
1043
+ "docs": "Enable or disable the shake menu for debugging/testing purposes",
1044
+ "complexTypes": [
1045
+ "SetShakeMenuOptions"
1046
+ ],
1047
+ "slug": "setshakemenu"
1048
+ },
1049
+ {
1050
+ "name": "isShakeMenuEnabled",
1051
+ "signature": "() => Promise<ShakeMenuEnabled>",
1052
+ "parameters": [],
1053
+ "returns": "Promise<ShakeMenuEnabled>",
1054
+ "tags": [
1055
+ {
1056
+ "name": "returns",
1057
+ "text": "The current state of shake menu"
1058
+ },
1059
+ {
1060
+ "name": "throws",
1061
+ "text": "{Error}"
1062
+ },
1063
+ {
1064
+ "name": "since",
1065
+ "text": "7.5.0"
1066
+ }
1067
+ ],
1068
+ "docs": "Get the current state of the shake menu",
1069
+ "complexTypes": [
1070
+ "ShakeMenuEnabled"
1071
+ ],
1072
+ "slug": "isshakemenuenabled"
989
1073
  }
990
1074
  ],
991
1075
  "properties": []
@@ -1595,6 +1679,86 @@
1595
1679
  }
1596
1680
  ]
1597
1681
  },
1682
+ {
1683
+ "name": "ListChannelsResult",
1684
+ "slug": "listchannelsresult",
1685
+ "docs": "",
1686
+ "tags": [],
1687
+ "methods": [],
1688
+ "properties": [
1689
+ {
1690
+ "name": "channels",
1691
+ "tags": [
1692
+ {
1693
+ "text": "7.5.0",
1694
+ "name": "since"
1695
+ }
1696
+ ],
1697
+ "docs": "List of available channels",
1698
+ "complexTypes": [
1699
+ "ChannelInfo"
1700
+ ],
1701
+ "type": "ChannelInfo[]"
1702
+ }
1703
+ ]
1704
+ },
1705
+ {
1706
+ "name": "ChannelInfo",
1707
+ "slug": "channelinfo",
1708
+ "docs": "",
1709
+ "tags": [],
1710
+ "methods": [],
1711
+ "properties": [
1712
+ {
1713
+ "name": "id",
1714
+ "tags": [
1715
+ {
1716
+ "text": "7.5.0",
1717
+ "name": "since"
1718
+ }
1719
+ ],
1720
+ "docs": "The channel ID",
1721
+ "complexTypes": [],
1722
+ "type": "string"
1723
+ },
1724
+ {
1725
+ "name": "name",
1726
+ "tags": [
1727
+ {
1728
+ "text": "7.5.0",
1729
+ "name": "since"
1730
+ }
1731
+ ],
1732
+ "docs": "The channel name",
1733
+ "complexTypes": [],
1734
+ "type": "string"
1735
+ },
1736
+ {
1737
+ "name": "public",
1738
+ "tags": [
1739
+ {
1740
+ "text": "7.5.0",
1741
+ "name": "since"
1742
+ }
1743
+ ],
1744
+ "docs": "Whether this is a public channel",
1745
+ "complexTypes": [],
1746
+ "type": "boolean"
1747
+ },
1748
+ {
1749
+ "name": "allow_self_set",
1750
+ "tags": [
1751
+ {
1752
+ "text": "7.5.0",
1753
+ "name": "since"
1754
+ }
1755
+ ],
1756
+ "docs": "Whether devices can self-assign to this channel",
1757
+ "complexTypes": [],
1758
+ "type": "boolean"
1759
+ }
1760
+ ]
1761
+ },
1598
1762
  {
1599
1763
  "name": "SetCustomIdOptions",
1600
1764
  "slug": "setcustomidoptions",
@@ -1900,6 +2064,38 @@
1900
2064
  "type": "boolean"
1901
2065
  }
1902
2066
  ]
2067
+ },
2068
+ {
2069
+ "name": "SetShakeMenuOptions",
2070
+ "slug": "setshakemenuoptions",
2071
+ "docs": "",
2072
+ "tags": [],
2073
+ "methods": [],
2074
+ "properties": [
2075
+ {
2076
+ "name": "enabled",
2077
+ "tags": [],
2078
+ "docs": "",
2079
+ "complexTypes": [],
2080
+ "type": "boolean"
2081
+ }
2082
+ ]
2083
+ },
2084
+ {
2085
+ "name": "ShakeMenuEnabled",
2086
+ "slug": "shakemenuenabled",
2087
+ "docs": "",
2088
+ "tags": [],
2089
+ "methods": [],
2090
+ "properties": [
2091
+ {
2092
+ "name": "enabled",
2093
+ "tags": [],
2094
+ "docs": "",
2095
+ "complexTypes": [],
2096
+ "type": "boolean"
2097
+ }
2098
+ ]
1903
2099
  }
1904
2100
  ],
1905
2101
  "enums": [],
@@ -2136,7 +2332,7 @@
2136
2332
  "name": "directUpdate",
2137
2333
  "tags": [
2138
2334
  {
2139
- "text": "undefined",
2335
+ "text": "false",
2140
2336
  "name": "default"
2141
2337
  },
2142
2338
  {
@@ -2144,7 +2340,23 @@
2144
2340
  "name": "since"
2145
2341
  }
2146
2342
  ],
2147
- "docs": "Make the plugin direct install the update when the app what just updated/installed. Only for autoUpdate mode.\n\nOnly available for Android and iOS.",
2343
+ "docs": "Configure when the plugin should direct install updates. Only for autoUpdate mode.\n- false: Never do direct updates (default behavior)\n- atInstall: Direct update only when app is installed/updated from store, otherwise use normal background update\n- always: Always do direct updates immediately when available\n- true: (deprecated) Same as \"always\" for backward compatibility\n\nOnly available for Android and iOS.",
2344
+ "complexTypes": [],
2345
+ "type": "boolean | 'always' | 'atInstall' | undefined"
2346
+ },
2347
+ {
2348
+ "name": "autoSplashscreen",
2349
+ "tags": [
2350
+ {
2351
+ "text": "false",
2352
+ "name": "default"
2353
+ },
2354
+ {
2355
+ "text": "7.6.0",
2356
+ "name": "since"
2357
+ }
2358
+ ],
2359
+ "docs": "Automatically handle splashscreen hiding when using directUpdate. When enabled, the plugin will automatically hide the splashscreen after updates are applied or when no update is needed.\nThis removes the need to manually listen for appReady events and call SplashScreen.hide().\nOnly works when directUpdate is set to \"atInstall\", \"always\", or true.\nRequires the @capacitor/splash-screen plugin to be installed and configured with launchAutoHide: false.\n\nOnly available for Android and iOS.",
2148
2360
  "complexTypes": [],
2149
2361
  "type": "boolean | undefined"
2150
2362
  },
@@ -2351,6 +2563,22 @@
2351
2563
  "docs": "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",
2352
2564
  "complexTypes": [],
2353
2565
  "type": "boolean | undefined"
2566
+ },
2567
+ {
2568
+ "name": "shakeMenu",
2569
+ "tags": [
2570
+ {
2571
+ "text": "false",
2572
+ "name": "default"
2573
+ },
2574
+ {
2575
+ "text": "7.5.0",
2576
+ "name": "since"
2577
+ }
2578
+ ],
2579
+ "docs": "Enable shake gesture to show update menu for debugging/testing purposes",
2580
+ "complexTypes": [],
2581
+ "type": "boolean | undefined"
2354
2582
  }
2355
2583
  ],
2356
2584
  "docs": "CapacitorUpdater can be configured with these options:"