@capgo/capacitor-updater 7.5.1 → 7.7.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.
package/README.md CHANGED
@@ -225,34 +225,35 @@ Capacitor Updater works by unzipping a compiled app bundle to the native device
225
225
 
226
226
  CapacitorUpdater can be configured with these options:
227
227
 
228
- | Prop | Type | Description | Default | Since |
229
- | ---------------------------- | -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------- | ------- |
230
- | **`appReadyTimeout`** | <code>number</code> | Configure the number of milliseconds the native plugin should wait before considering an update 'failed'. Only available for Android and iOS. | <code>10000 // (10 seconds)</code> | |
231
- | **`responseTimeout`** | <code>number</code> | Configure the number of milliseconds the native plugin should wait before considering API timeout. Only available for Android and iOS. | <code>20 // (20 second)</code> | |
232
- | **`autoDeleteFailed`** | <code>boolean</code> | Configure whether the plugin should use automatically delete failed bundles. Only available for Android and iOS. | <code>true</code> | |
233
- | **`autoDeletePrevious`** | <code>boolean</code> | Configure whether the plugin should use automatically delete previous bundles after a successful update. Only available for Android and iOS. | <code>true</code> | |
234
- | **`autoUpdate`** | <code>boolean</code> | Configure whether the plugin should use Auto Update via an update server. Only available for Android and iOS. | <code>true</code> | |
235
- | **`resetWhenUpdate`** | <code>boolean</code> | Automatically delete previous downloaded bundles when a newer native app bundle is installed to the device. Only available for Android and iOS. | <code>true</code> | |
236
- | **`updateUrl`** | <code>string</code> | Configure the URL / endpoint to which update checks are sent. Only available for Android and iOS. | <code>https://plugin.capgo.app/updates</code> | |
237
- | **`channelUrl`** | <code>string</code> | Configure the URL / endpoint for channel operations. Only available for Android and iOS. | <code>https://plugin.capgo.app/channel_self</code> | |
238
- | **`statsUrl`** | <code>string</code> | Configure the URL / endpoint to which update statistics are sent. Only available for Android and iOS. Set to "" to disable stats reporting. | <code>https://plugin.capgo.app/stats</code> | |
239
- | **`publicKey`** | <code>string</code> | Configure the public key for end to end live update encryption Version 2 Only available for Android and iOS. | <code>undefined</code> | 6.2.0 |
240
- | **`version`** | <code>string</code> | Configure the current version of the app. This will be used for the first update request. If not set, the plugin will get the version from the native code. Only available for Android and iOS. | <code>undefined</code> | 4.17.48 |
241
- | **`directUpdate`** | <code>boolean</code> | Make the plugin direct install the update when the app what just updated/installed. Only for autoUpdate mode. Only available for Android and iOS. | <code>undefined</code> | 5.1.0 |
242
- | **`periodCheckDelay`** | <code>number</code> | Configure the delay period for period update check. the unit is in seconds. Only available for Android and iOS. Cannot be less than 600 seconds (10 minutes). | <code>600 // (10 minutes)</code> | |
243
- | **`localS3`** | <code>boolean</code> | Configure the CLI to use a local server for testing or self-hosted update server. | <code>undefined</code> | 4.17.48 |
244
- | **`localHost`** | <code>string</code> | Configure the CLI to use a local server for testing or self-hosted update server. | <code>undefined</code> | 4.17.48 |
245
- | **`localWebHost`** | <code>string</code> | Configure the CLI to use a local server for testing or self-hosted update server. | <code>undefined</code> | 4.17.48 |
246
- | **`localSupa`** | <code>string</code> | Configure the CLI to use a local server for testing or self-hosted update server. | <code>undefined</code> | 4.17.48 |
247
- | **`localSupaAnon`** | <code>string</code> | Configure the CLI to use a local server for testing. | <code>undefined</code> | 4.17.48 |
248
- | **`localApi`** | <code>string</code> | Configure the CLI to use a local api for testing. | <code>undefined</code> | 6.3.3 |
249
- | **`localApiFiles`** | <code>string</code> | Configure the CLI to use a local file api for testing. | <code>undefined</code> | 6.3.3 |
250
- | **`allowModifyUrl`** | <code>boolean</code> | Allow the plugin to modify the updateUrl, statsUrl and channelUrl dynamically from the JavaScript side. | <code>false</code> | 5.4.0 |
251
- | **`defaultChannel`** | <code>string</code> | Set the default channel for the app in the config. Case sensitive. This will setting will override the default channel set in the cloud, but will still respect overrides made in the cloud. | <code>undefined</code> | 5.5.0 |
252
- | **`appId`** | <code>string</code> | Configure the app id for the app in the config. | <code>undefined</code> | 6.0.0 |
253
- | **`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 |
254
- | **`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 |
255
- | **`shakeMenu`** | <code>boolean</code> | Enable shake gesture to show update menu for debugging/testing purposes | <code>false</code> | 7.5.0 |
228
+ | Prop | Type | Description | Default | Since |
229
+ | ---------------------------- | ----------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------- | ------- |
230
+ | **`appReadyTimeout`** | <code>number</code> | Configure the number of milliseconds the native plugin should wait before considering an update 'failed'. Only available for Android and iOS. | <code>10000 // (10 seconds)</code> | |
231
+ | **`responseTimeout`** | <code>number</code> | Configure the number of milliseconds the native plugin should wait before considering API timeout. Only available for Android and iOS. | <code>20 // (20 second)</code> | |
232
+ | **`autoDeleteFailed`** | <code>boolean</code> | Configure whether the plugin should use automatically delete failed bundles. Only available for Android and iOS. | <code>true</code> | |
233
+ | **`autoDeletePrevious`** | <code>boolean</code> | Configure whether the plugin should use automatically delete previous bundles after a successful update. Only available for Android and iOS. | <code>true</code> | |
234
+ | **`autoUpdate`** | <code>boolean</code> | Configure whether the plugin should use Auto Update via an update server. Only available for Android and iOS. | <code>true</code> | |
235
+ | **`resetWhenUpdate`** | <code>boolean</code> | Automatically delete previous downloaded bundles when a newer native app bundle is installed to the device. Only available for Android and iOS. | <code>true</code> | |
236
+ | **`updateUrl`** | <code>string</code> | Configure the URL / endpoint to which update checks are sent. Only available for Android and iOS. | <code>https://plugin.capgo.app/updates</code> | |
237
+ | **`channelUrl`** | <code>string</code> | Configure the URL / endpoint for channel operations. Only available for Android and iOS. | <code>https://plugin.capgo.app/channel_self</code> | |
238
+ | **`statsUrl`** | <code>string</code> | Configure the URL / endpoint to which update statistics are sent. Only available for Android and iOS. Set to "" to disable stats reporting. | <code>https://plugin.capgo.app/stats</code> | |
239
+ | **`publicKey`** | <code>string</code> | Configure the public key for end to end live update encryption Version 2 Only available for Android and iOS. | <code>undefined</code> | 6.2.0 |
240
+ | **`version`** | <code>string</code> | Configure the current version of the app. This will be used for the first update request. If not set, the plugin will get the version from the native code. Only available for Android and iOS. | <code>undefined</code> | 4.17.48 |
241
+ | **`directUpdate`** | <code>boolean \| 'always' \| 'atInstall'</code> | Configure when the plugin should direct install updates. Only for autoUpdate mode. - false: Never do direct updates (default behavior) - atInstall: Direct update only when app is installed/updated from store, otherwise use normal background update - always: Always do direct updates immediately when available - true: (deprecated) Same as "always" for backward compatibility Only available for Android and iOS. | <code>false</code> | 5.1.0 |
242
+ | **`autoSplashscreen`** | <code>boolean</code> | 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. This removes the need to manually listen for appReady events and call SplashScreen.hide(). Only works when directUpdate is set to "atInstall", "always", or true. Requires the @capacitor/splash-screen plugin to be installed and configured with launchAutoHide: false. Only available for Android and iOS. | <code>false</code> | 7.6.0 |
243
+ | **`periodCheckDelay`** | <code>number</code> | Configure the delay period for period update check. the unit is in seconds. Only available for Android and iOS. Cannot be less than 600 seconds (10 minutes). | <code>600 // (10 minutes)</code> | |
244
+ | **`localS3`** | <code>boolean</code> | Configure the CLI to use a local server for testing or self-hosted update server. | <code>undefined</code> | 4.17.48 |
245
+ | **`localHost`** | <code>string</code> | Configure the CLI to use a local server for testing or self-hosted update server. | <code>undefined</code> | 4.17.48 |
246
+ | **`localWebHost`** | <code>string</code> | Configure the CLI to use a local server for testing or self-hosted update server. | <code>undefined</code> | 4.17.48 |
247
+ | **`localSupa`** | <code>string</code> | Configure the CLI to use a local server for testing or self-hosted update server. | <code>undefined</code> | 4.17.48 |
248
+ | **`localSupaAnon`** | <code>string</code> | Configure the CLI to use a local server for testing. | <code>undefined</code> | 4.17.48 |
249
+ | **`localApi`** | <code>string</code> | Configure the CLI to use a local api for testing. | <code>undefined</code> | 6.3.3 |
250
+ | **`localApiFiles`** | <code>string</code> | Configure the CLI to use a local file api for testing. | <code>undefined</code> | 6.3.3 |
251
+ | **`allowModifyUrl`** | <code>boolean</code> | Allow the plugin to modify the updateUrl, statsUrl and channelUrl dynamically from the JavaScript side. | <code>false</code> | 5.4.0 |
252
+ | **`defaultChannel`** | <code>string</code> | Set the default channel for the app in the config. Case sensitive. This will setting will override the default channel set in the cloud, but will still respect overrides made in the cloud. | <code>undefined</code> | 5.5.0 |
253
+ | **`appId`** | <code>string</code> | Configure the app id for the app in the config. | <code>undefined</code> | 6.0.0 |
254
+ | **`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 |
255
+ | **`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 |
256
+ | **`shakeMenu`** | <code>boolean</code> | Enable shake gesture to show update menu for debugging/testing purposes | <code>false</code> | 7.5.0 |
256
257
 
257
258
  ### Examples
258
259
 
@@ -274,6 +275,7 @@ In `capacitor.config.json`:
274
275
  "publicKey": undefined,
275
276
  "version": undefined,
276
277
  "directUpdate": undefined,
278
+ "autoSplashscreen": undefined,
277
279
  "periodCheckDelay": undefined,
278
280
  "localS3": undefined,
279
281
  "localHost": undefined,
@@ -315,6 +317,7 @@ const config: CapacitorConfig = {
315
317
  publicKey: undefined,
316
318
  version: undefined,
317
319
  directUpdate: undefined,
320
+ autoSplashscreen: undefined,
318
321
  periodCheckDelay: undefined,
319
322
  localS3: undefined,
320
323
  localHost: undefined,
@@ -60,7 +60,7 @@ public class CapacitorUpdaterPlugin extends Plugin {
60
60
  private static final String statsUrlDefault = "https://plugin.capgo.app/stats";
61
61
  private static final String channelUrlDefault = "https://plugin.capgo.app/channel_self";
62
62
 
63
- private final String PLUGIN_VERSION = "7.5.1";
63
+ private final String PLUGIN_VERSION = "7.7.0";
64
64
  private static final String DELAY_CONDITION_PREFERENCES = "";
65
65
 
66
66
  private SharedPreferences.Editor editor;
@@ -78,6 +78,9 @@ public class CapacitorUpdaterPlugin extends Plugin {
78
78
  private Thread backgroundTask;
79
79
  private Boolean taskRunning = false;
80
80
  private Boolean keepUrlPathAfterReload = false;
81
+ private Boolean autoSplashscreen = false;
82
+ private String directUpdateMode = "false";
83
+ private Boolean wasRecentlyInstalledOrUpdated = false;
81
84
  Boolean shakeMenuEnabled = false;
82
85
 
83
86
  private Boolean isPreviousMainActivity = true;
@@ -157,7 +160,21 @@ public class CapacitorUpdaterPlugin extends Plugin {
157
160
  .readTimeout(this.implementation.timeout, TimeUnit.MILLISECONDS)
158
161
  .writeTimeout(this.implementation.timeout, TimeUnit.MILLISECONDS)
159
162
  .build();
160
- this.implementation.directUpdate = this.getConfig().getBoolean("directUpdate", false);
163
+ // Handle directUpdate configuration - support string values and backward compatibility
164
+ String directUpdateConfig = this.getConfig().getString("directUpdate", null);
165
+ if (directUpdateConfig != null) {
166
+ this.directUpdateMode = directUpdateConfig;
167
+ this.implementation.directUpdate = directUpdateConfig.equals("always") || directUpdateConfig.equals("atInstall");
168
+ } else {
169
+ Boolean directUpdateBool = this.getConfig().getBoolean("directUpdate", false);
170
+ if (directUpdateBool) {
171
+ this.directUpdateMode = "always"; // backward compatibility: true = always
172
+ this.implementation.directUpdate = true;
173
+ } else {
174
+ this.directUpdateMode = "false";
175
+ this.implementation.directUpdate = false;
176
+ }
177
+ }
161
178
  this.currentVersionNative = new Version(this.getConfig().getString("version", pInfo.versionName));
162
179
  this.delayUpdateUtils = new DelayUpdateUtils(
163
180
  this.prefs,
@@ -226,10 +243,14 @@ public class CapacitorUpdaterPlugin extends Plugin {
226
243
  this.autoUpdate = this.getConfig().getBoolean("autoUpdate", true);
227
244
  this.appReadyTimeout = this.getConfig().getInt("appReadyTimeout", 10000);
228
245
  this.keepUrlPathAfterReload = this.getConfig().getBoolean("keepUrlPathAfterReload", false);
246
+ this.autoSplashscreen = this.getConfig().getBoolean("autoSplashscreen", false);
229
247
  this.implementation.timeout = this.getConfig().getInt("responseTimeout", 20) * 1000;
230
248
  this.shakeMenuEnabled = this.getConfig().getBoolean("shakeMenu", false);
231
249
  boolean resetWhenUpdate = this.getConfig().getBoolean("resetWhenUpdate", true);
232
250
 
251
+ // Check if app was recently installed/updated BEFORE cleanupObsoleteVersions updates LatestVersionNative
252
+ this.wasRecentlyInstalledOrUpdated = this.checkIfRecentlyInstalledOrUpdated();
253
+
233
254
  this.implementation.autoReset();
234
255
  if (resetWhenUpdate) {
235
256
  this.cleanupObsoleteVersions();
@@ -261,22 +282,83 @@ public class CapacitorUpdaterPlugin extends Plugin {
261
282
  }
262
283
 
263
284
  private void sendReadyToJs(final BundleInfo current, final String msg) {
264
- logger.info("sendReadyToJs");
285
+ sendReadyToJs(current, msg, false);
286
+ }
287
+
288
+ private void sendReadyToJs(final BundleInfo current, final String msg, final boolean isDirectUpdate) {
289
+ logger.info("sendReadyToJs: " + msg);
265
290
  final JSObject ret = new JSObject();
266
291
  ret.put("bundle", mapToJSObject(current.toJSONMap()));
267
292
  ret.put("status", msg);
268
- startNewThread(() -> {
269
- logger.info("semaphoreReady sendReadyToJs");
270
- semaphoreWait(CapacitorUpdaterPlugin.this.appReadyTimeout);
271
- logger.info("semaphoreReady sendReadyToJs done");
272
- CapacitorUpdaterPlugin.this.notifyListeners("appReady", ret);
273
- });
293
+
294
+ // No need to wait for semaphore anymore since _reload() has already waited
295
+ this.notifyListeners("appReady", ret);
296
+
297
+ // Auto hide splashscreen if enabled and this is a direct update
298
+ if (this.autoSplashscreen && isDirectUpdate) {
299
+ this.hideSplashscreen();
300
+ }
301
+ }
302
+
303
+ private void hideSplashscreen() {
304
+ try {
305
+ // Use JavaScript evaluation to hide the splashscreen - simpler and more reliable
306
+ getBridge()
307
+ .getWebView()
308
+ .post(() -> {
309
+ getBridge()
310
+ .eval(
311
+ "(function() { " +
312
+ " if (window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.SplashScreen) { " +
313
+ " window.Capacitor.Plugins.SplashScreen.hide(); " +
314
+ " } " +
315
+ "})()",
316
+ null
317
+ );
318
+ });
319
+ logger.info("Splashscreen hidden automatically via JavaScript");
320
+ } catch (Exception e) {
321
+ logger.error("Error hiding splashscreen: " + e.getMessage());
322
+ }
323
+ }
324
+
325
+ private boolean checkIfRecentlyInstalledOrUpdated() {
326
+ String currentVersion = this.currentVersionNative.getOriginalString();
327
+ String lastKnownVersion = this.prefs.getString("LatestVersionNative", "");
328
+
329
+ if (lastKnownVersion.isEmpty()) {
330
+ // First time running, consider it as recently installed
331
+ return true;
332
+ } else if (!lastKnownVersion.equals(currentVersion)) {
333
+ // Version changed, consider it as recently updated
334
+ return true;
335
+ }
336
+
337
+ return false;
338
+ }
339
+
340
+ private boolean shouldUseDirectUpdate() {
341
+ switch (this.directUpdateMode) {
342
+ case "false":
343
+ return false;
344
+ case "always":
345
+ return true;
346
+ case "atInstall":
347
+ if (this.wasRecentlyInstalledOrUpdated) {
348
+ // Reset the flag after first use to prevent subsequent foreground events from using direct update
349
+ this.wasRecentlyInstalledOrUpdated = false;
350
+ return true;
351
+ }
352
+ return false;
353
+ default:
354
+ return false;
355
+ }
274
356
  }
275
357
 
276
358
  private void directUpdateFinish(final BundleInfo latest) {
277
359
  CapacitorUpdaterPlugin.this.implementation.set(latest);
278
360
  CapacitorUpdaterPlugin.this._reload();
279
- sendReadyToJs(latest, "update installed");
361
+ sendReadyToJs(latest, "update installed", true);
280
362
  }
281
363
 
282
364
  private void cleanupObsoleteVersions() {
@@ -688,6 +770,10 @@ public class CapacitorUpdaterPlugin extends Plugin {
688
770
 
689
771
  this.checkAppReady();
690
772
  this.notifyListeners("appReloaded", new JSObject());
773
+
774
+ // Wait for the reload to complete (until notifyAppReady is called)
775
+ this.semaphoreWait(this.appReadyTimeout);
776
+
691
777
  return true;
692
778
  }
693
779
 
@@ -1026,6 +1112,16 @@ public class CapacitorUpdaterPlugin extends Plugin {
1026
1112
  }
1027
1113
 
1028
1114
  private void endBackGroundTaskWithNotif(String msg, String latestVersionName, BundleInfo current, Boolean error) {
1115
+ endBackGroundTaskWithNotif(msg, latestVersionName, current, error, false);
1116
+ }
1117
+
1118
+ private void endBackGroundTaskWithNotif(
1119
+ String msg,
1120
+ String latestVersionName,
1121
+ BundleInfo current,
1122
+ Boolean error,
1123
+ Boolean isDirectUpdate
1124
+ ) {
1029
1125
  if (error) {
1030
1126
  logger.info(
1031
1127
  "endBackGroundTaskWithNotif error: " +
@@ -1043,15 +1139,14 @@ public class CapacitorUpdaterPlugin extends Plugin {
1043
1139
  final JSObject ret = new JSObject();
1044
1140
  ret.put("bundle", mapToJSObject(current.toJSONMap()));
1045
1141
  this.notifyListeners("noNeedUpdate", ret);
1046
- this.sendReadyToJs(current, msg);
1142
+ this.sendReadyToJs(current, msg, isDirectUpdate);
1047
1143
  this.backgroundDownloadTask = null;
1048
1144
  logger.info("endBackGroundTaskWithNotif " + msg);
1049
1145
  }
1050
1146
 
1051
1147
  private Thread backgroundDownload() {
1052
- String messageUpdate = this.implementation.directUpdate
1053
- ? "Update will occur now."
1054
- : "Update will occur next time app moves to background.";
1148
+ boolean shouldDirectUpdate = this.shouldUseDirectUpdate();
1149
+ String messageUpdate = shouldDirectUpdate ? "Update will occur now." : "Update will occur next time app moves to background.";
1055
1150
  return startNewThread(() -> {
1056
1151
  logger.info("Check for update via: " + CapacitorUpdaterPlugin.this.updateUrl);
1057
1152
  CapacitorUpdaterPlugin.this.implementation.getLatest(CapacitorUpdaterPlugin.this.updateUrl, null, res -> {
@@ -1069,7 +1164,8 @@ public class CapacitorUpdaterPlugin extends Plugin {
1069
1164
  jsRes.getString("message"),
1070
1165
  current.getVersionName(),
1071
1166
  current,
1072
- true
1167
+ true,
1168
+ shouldDirectUpdate
1073
1169
  );
1074
1170
  return;
1075
1171
  }
@@ -1078,14 +1174,15 @@ public class CapacitorUpdaterPlugin extends Plugin {
1078
1174
 
1079
1175
  if ("builtin".equals(latestVersionName)) {
1080
1176
  logger.info("Latest version is builtin");
1081
- if (CapacitorUpdaterPlugin.this.implementation.directUpdate) {
1177
+ if (shouldDirectUpdate) {
1082
1178
  logger.info("Direct update to builtin version");
1083
1179
  this._reset(false);
1084
1180
  CapacitorUpdaterPlugin.this.endBackGroundTaskWithNotif(
1085
1181
  "Updated to builtin version",
1086
1182
  latestVersionName,
1087
1183
  CapacitorUpdaterPlugin.this.implementation.getCurrentBundle(),
1088
- false
1184
+ false,
1185
+ true
1089
1186
  );
1090
1187
  } else {
1091
1188
  logger.info("Setting next bundle to builtin");
@@ -1106,7 +1203,8 @@ public class CapacitorUpdaterPlugin extends Plugin {
1106
1203
  "Error no url or wrong format",
1107
1204
  current.getVersionName(),
1108
1205
  current,
1109
- true
1206
+ true,
1207
+ shouldDirectUpdate
1110
1208
  );
1111
1209
  return;
1112
1210
  }
@@ -1124,13 +1222,14 @@ public class CapacitorUpdaterPlugin extends Plugin {
1124
1222
  "Latest bundle already exists, and is in error state. Aborting update.",
1125
1223
  latestVersionName,
1126
1224
  current,
1127
- true
1225
+ true,
1226
+ shouldDirectUpdate
1128
1227
  );
1129
1228
  return;
1130
1229
  }
1131
1230
  if (latest.isDownloaded()) {
1132
1231
  logger.info("Latest bundle already exists and download is NOT required. " + messageUpdate);
1133
- if (CapacitorUpdaterPlugin.this.implementation.directUpdate) {
1232
+ if (shouldDirectUpdate) {
1134
1233
  Gson gson = new Gson();
1135
1234
  String delayUpdatePreferences = prefs.getString(DelayUpdateUtils.DELAY_CONDITION_PREFERENCES, "[]");
1136
1235
  Type type = new TypeToken<ArrayList<DelayCondition>>() {}.getType();
@@ -1141,7 +1240,8 @@ public class CapacitorUpdaterPlugin extends Plugin {
1141
1240
  "Update delayed until delay conditions met",
1142
1241
  latestVersionName,
1143
1242
  latest,
1144
- false
1243
+ false,
1244
+ shouldDirectUpdate
1145
1245
  );
1146
1246
  return;
1147
1247
  }
@@ -1151,7 +1251,8 @@ public class CapacitorUpdaterPlugin extends Plugin {
1151
1251
  "Update installed",
1152
1252
  latestVersionName,
1153
1253
  latest,
1154
- false
1254
+ false,
1255
+ true
1155
1256
  );
1156
1257
  } else {
1157
1258
  CapacitorUpdaterPlugin.this.notifyListeners("updateAvailable", ret);
@@ -1218,7 +1319,8 @@ public class CapacitorUpdaterPlugin extends Plugin {
1218
1319
  "Error downloading file",
1219
1320
  latestVersionName,
1220
1321
  CapacitorUpdaterPlugin.this.implementation.getCurrentBundle(),
1221
- true
1322
+ true,
1323
+ shouldDirectUpdate
1222
1324
  );
1223
1325
  }
1224
1326
  });
@@ -1232,7 +1334,8 @@ public class CapacitorUpdaterPlugin extends Plugin {
1232
1334
  "Error parsing JSON",
1233
1335
  current.getVersionName(),
1234
1336
  current,
1235
- true
1337
+ true,
1338
+ shouldDirectUpdate
1236
1339
  );
1237
1340
  }
1238
1341
  });
@@ -1378,62 +1481,82 @@ public class CapacitorUpdaterPlugin extends Plugin {
1378
1481
 
1379
1482
  @Override
1380
1483
  public void handleOnStart() {
1381
- if (isPreviousMainActivity) {
1382
- this.appMovedToForeground();
1383
- }
1384
- logger.info("onActivityStarted " + getActivity().getClass().getName());
1385
- isPreviousMainActivity = true;
1484
+ try {
1485
+ if (isPreviousMainActivity) {
1486
+ this.appMovedToForeground();
1487
+ }
1488
+ logger.info("onActivityStarted " + getActivity().getClass().getName());
1489
+ isPreviousMainActivity = true;
1386
1490
 
1387
- // Initialize shake menu if enabled and activity is BridgeActivity
1388
- if (shakeMenuEnabled && getActivity() instanceof com.getcapacitor.BridgeActivity && shakeMenu == null) {
1389
- try {
1390
- shakeMenu = new ShakeMenu(this, (com.getcapacitor.BridgeActivity) getActivity(), logger);
1391
- logger.info("Shake menu initialized");
1392
- } catch (Exception e) {
1393
- logger.error("Failed to initialize shake menu: " + e.getMessage());
1491
+ // Initialize shake menu if enabled and activity is BridgeActivity
1492
+ if (shakeMenuEnabled && getActivity() instanceof com.getcapacitor.BridgeActivity && shakeMenu == null) {
1493
+ try {
1494
+ shakeMenu = new ShakeMenu(this, (com.getcapacitor.BridgeActivity) getActivity(), logger);
1495
+ logger.info("Shake menu initialized");
1496
+ } catch (Exception e) {
1497
+ logger.error("Failed to initialize shake menu: " + e.getMessage());
1498
+ }
1394
1499
  }
1500
+ } catch (Exception e) {
1501
+ logger.error("Failed to run handleOnStart: " + e.getMessage());
1395
1502
  }
1396
1503
  }
1397
1504
 
1398
1505
  @Override
1399
1506
  public void handleOnStop() {
1400
- isPreviousMainActivity = isMainActivity();
1401
- if (isPreviousMainActivity) {
1402
- this.appMovedToBackground();
1507
+ try {
1508
+ isPreviousMainActivity = isMainActivity();
1509
+ if (isPreviousMainActivity) {
1510
+ this.appMovedToBackground();
1511
+ }
1512
+ } catch (Exception e) {
1513
+ logger.error("Failed to run handleOnStop: " + e.getMessage());
1403
1514
  }
1404
1515
  }
1405
1516
 
1406
1517
  @Override
1407
1518
  public void handleOnResume() {
1408
- if (backgroundTask != null && taskRunning) {
1409
- backgroundTask.interrupt();
1519
+ try {
1520
+ if (backgroundTask != null && taskRunning) {
1521
+ backgroundTask.interrupt();
1522
+ }
1523
+ this.implementation.activity = getActivity();
1524
+ } catch (Exception e) {
1525
+ logger.error("Failed to run handleOnResume: " + e.getMessage());
1410
1526
  }
1411
- this.implementation.activity = getActivity();
1412
1527
  }
1413
1528
 
1414
1529
  @Override
1415
1530
  public void handleOnPause() {
1416
- this.implementation.activity = getActivity();
1531
+ try {
1532
+ this.implementation.activity = getActivity();
1533
+ } catch (Exception e) {
1534
+ logger.error("Failed to run handleOnPause: " + e.getMessage());
1535
+ }
1417
1536
  }
1418
1537
 
1419
1538
  @Override
1420
1539
  public void handleOnDestroy() {
1421
- logger.info("onActivityDestroyed " + getActivity().getClass().getName());
1422
- this.implementation.activity = getActivity();
1423
- counterActivityCreate--;
1424
- if (counterActivityCreate == 0) {
1425
- this.appKilled();
1426
- }
1540
+ try {
1541
+ logger.info("onActivityDestroyed " + getActivity().getClass().getName());
1542
+ this.implementation.activity = getActivity();
1543
+ counterActivityCreate--;
1544
+ if (counterActivityCreate == 0) {
1545
+ this.appKilled();
1546
+ }
1427
1547
 
1428
- // Clean up shake menu
1429
- if (shakeMenu != null) {
1430
- try {
1431
- shakeMenu.stop();
1432
- shakeMenu = null;
1433
- logger.info("Shake menu cleaned up");
1434
- } catch (Exception e) {
1435
- logger.error("Failed to clean up shake menu: " + e.getMessage());
1548
+ // Clean up shake menu
1549
+ if (shakeMenu != null) {
1550
+ try {
1551
+ shakeMenu.stop();
1552
+ shakeMenu = null;
1553
+ logger.info("Shake menu cleaned up");
1554
+ } catch (Exception e) {
1555
+ logger.error("Failed to clean up shake menu: " + e.getMessage());
1556
+ }
1436
1557
  }
1558
+ } catch (Exception e) {
1559
+ logger.error("Failed to run handleOnDestroy: " + e.getMessage());
1437
1560
  }
1438
1561
  }
1439
1562
 
package/dist/docs.json CHANGED
@@ -2332,7 +2332,7 @@
2332
2332
  "name": "directUpdate",
2333
2333
  "tags": [
2334
2334
  {
2335
- "text": "undefined",
2335
+ "text": "false",
2336
2336
  "name": "default"
2337
2337
  },
2338
2338
  {
@@ -2340,7 +2340,23 @@
2340
2340
  "name": "since"
2341
2341
  }
2342
2342
  ],
2343
- "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.",
2344
2360
  "complexTypes": [],
2345
2361
  "type": "boolean | undefined"
2346
2362
  },
@@ -106,14 +106,30 @@ declare module '@capacitor/cli' {
106
106
  */
107
107
  version?: string;
108
108
  /**
109
- * Make the plugin direct install the update when the app what just updated/installed. Only for autoUpdate mode.
109
+ * Configure when the plugin should direct install updates. Only for autoUpdate mode.
110
+ * - false: Never do direct updates (default behavior)
111
+ * - atInstall: Direct update only when app is installed/updated from store, otherwise use normal background update
112
+ * - always: Always do direct updates immediately when available
113
+ * - true: (deprecated) Same as "always" for backward compatibility
110
114
  *
111
115
  * Only available for Android and iOS.
112
116
  *
113
- * @default undefined
117
+ * @default false
114
118
  * @since 5.1.0
115
119
  */
116
- directUpdate?: boolean;
120
+ directUpdate?: boolean | 'atInstall' | 'always';
121
+ /**
122
+ * 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.
123
+ * This removes the need to manually listen for appReady events and call SplashScreen.hide().
124
+ * Only works when directUpdate is set to "atInstall", "always", or true.
125
+ * Requires the @capacitor/splash-screen plugin to be installed and configured with launchAutoHide: false.
126
+ *
127
+ * Only available for Android and iOS.
128
+ *
129
+ * @default false
130
+ * @since 7.6.0
131
+ */
132
+ autoSplashscreen?: boolean;
117
133
  /**
118
134
  * Configure the delay period for period update check. the unit is in seconds.
119
135
  *
@@ -1 +1 @@
1
- {"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"AAAA;;;;GAIG","sourcesContent":["/*\n * This Source Code Form is subject to the terms of the Mozilla Public\n * License, v. 2.0. If a copy of the MPL was not distributed with this\n * file, You can obtain one at https://mozilla.org/MPL/2.0/.\n */\n\n/// <reference types=\"@capacitor/cli\" />\n\nimport type { PluginListenerHandle } from '@capacitor/core';\n\ndeclare module '@capacitor/cli' {\n export interface PluginsConfig {\n /**\n * CapacitorUpdater can be configured with these options:\n */\n CapacitorUpdater?: {\n /**\n * Configure the number of milliseconds the native plugin should wait before considering an update 'failed'.\n *\n * Only available for Android and iOS.\n *\n * @default 10000 // (10 seconds)\n * @example 1000 // (1 second)\n */\n appReadyTimeout?: number;\n /**\n * Configure the number of milliseconds the native plugin should wait before considering API timeout.\n *\n * Only available for Android and iOS.\n *\n * @default 20 // (20 second)\n * @example 10 // (10 second)\n */\n responseTimeout?: number;\n /**\n * Configure whether the plugin should use automatically delete failed bundles.\n *\n * Only available for Android and iOS.\n *\n * @default true\n * @example false\n */\n autoDeleteFailed?: boolean;\n\n /**\n * Configure whether the plugin should use automatically delete previous bundles after a successful update.\n *\n * Only available for Android and iOS.\n *\n * @default true\n * @example false\n */\n autoDeletePrevious?: boolean;\n\n /**\n * Configure whether the plugin should use Auto Update via an update server.\n *\n * Only available for Android and iOS.\n *\n * @default true\n * @example false\n */\n autoUpdate?: boolean;\n\n /**\n * Automatically delete previous downloaded bundles when a newer native app bundle is installed to the device.\n *\n * Only available for Android and iOS.\n *\n * @default true\n * @example false\n */\n resetWhenUpdate?: boolean;\n\n /**\n * Configure the URL / endpoint to which update checks are sent.\n *\n * Only available for Android and iOS.\n *\n * @default https://plugin.capgo.app/updates\n * @example https://example.com/api/auto_update\n */\n updateUrl?: string;\n\n /**\n * Configure the URL / endpoint for channel operations.\n *\n * Only available for Android and iOS.\n *\n * @default https://plugin.capgo.app/channel_self\n * @example https://example.com/api/channel\n */\n channelUrl?: string;\n\n /**\n * Configure the URL / endpoint to which update statistics are sent.\n *\n * Only available for Android and iOS. Set to \"\" to disable stats reporting.\n *\n * @default https://plugin.capgo.app/stats\n * @example https://example.com/api/stats\n */\n statsUrl?: string;\n /**\n * Configure the public key for end to end live update encryption Version 2\n *\n * Only available for Android and iOS.\n *\n * @default undefined\n * @since 6.2.0\n */\n publicKey?: string;\n\n /**\n * Configure the current version of the app. This will be used for the first update request.\n * If not set, the plugin will get the version from the native code.\n *\n * Only available for Android and iOS.\n *\n * @default undefined\n * @since 4.17.48\n */\n version?: string;\n /**\n * Make the plugin direct install the update when the app what just updated/installed. Only for autoUpdate mode.\n *\n * Only available for Android and iOS.\n *\n * @default undefined\n * @since 5.1.0\n */\n directUpdate?: boolean;\n\n /**\n * Configure the delay period for period update check. the unit is in seconds.\n *\n * Only available for Android and iOS.\n * Cannot be less than 600 seconds (10 minutes).\n *\n * @default 600 // (10 minutes)\n */\n periodCheckDelay?: number;\n\n /**\n * Configure the CLI to use a local server for testing or self-hosted update server.\n *\n *\n * @default undefined\n * @since 4.17.48\n */\n localS3?: boolean;\n /**\n * Configure the CLI to use a local server for testing or self-hosted update server.\n *\n *\n * @default undefined\n * @since 4.17.48\n */\n localHost?: string;\n /**\n * Configure the CLI to use a local server for testing or self-hosted update server.\n *\n *\n * @default undefined\n * @since 4.17.48\n */\n localWebHost?: string;\n /**\n * Configure the CLI to use a local server for testing or self-hosted update server.\n *\n *\n * @default undefined\n * @since 4.17.48\n */\n localSupa?: string;\n /**\n * Configure the CLI to use a local server for testing.\n *\n *\n * @default undefined\n * @since 4.17.48\n */\n localSupaAnon?: string;\n /**\n * Configure the CLI to use a local api for testing.\n *\n *\n * @default undefined\n * @since 6.3.3\n */\n localApi?: string;\n /**\n * Configure the CLI to use a local file api for testing.\n *\n *\n * @default undefined\n * @since 6.3.3\n */\n localApiFiles?: string;\n /**\n * Allow the plugin to modify the updateUrl, statsUrl and channelUrl dynamically from the JavaScript side.\n *\n *\n * @default false\n * @since 5.4.0\n */\n allowModifyUrl?: boolean;\n\n /**\n * Set the default channel for the app in the config. Case sensitive.\n * This will setting will override the default channel set in the cloud, but will still respect overrides made in the cloud.\n *\n *\n * @default undefined\n * @since 5.5.0\n */\n defaultChannel?: string;\n /**\n * Configure the app id for the app in the config.\n *\n * @default undefined\n * @since 6.0.0\n */\n appId?: string;\n\n /**\n * Configure the plugin to keep the URL path after a reload.\n * WARNING: When a reload is triggered, 'window.history' will be cleared.\n *\n * @default false\n * @since 6.8.0\n */\n keepUrlPathAfterReload?: boolean;\n /**\n * 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\n *\n * @default false\n * @since 7.3.0\n */\n disableJSLogging?: boolean;\n /**\n * Enable shake gesture to show update menu for debugging/testing purposes\n *\n * @default false\n * @since 7.5.0\n */\n shakeMenu?: boolean;\n };\n }\n}\n\nexport interface CapacitorUpdaterPlugin {\n /**\n * Notify Capacitor Updater that the current bundle is working (a rollback will occur if this method is not called on every app launch)\n * By default this method should be called in the first 10 sec after app launch, otherwise a rollback will occur.\n * Change this behaviour with {@link appReadyTimeout}\n *\n * @returns {Promise<AppReadyResult>} an Promise resolved directly\n * @throws {Error}\n */\n notifyAppReady(): Promise<AppReadyResult>;\n\n /**\n * Set the updateUrl for the app, this will be used to check for updates.\n *\n * @param options contains the URL to use for checking for updates.\n * @returns {Promise<void>}\n * @throws {Error}\n * @since 5.4.0\n */\n setUpdateUrl(options: UpdateUrl): Promise<void>;\n\n /**\n * Set the statsUrl for the app, this will be used to send statistics. Passing an empty string will disable statistics gathering.\n *\n * @param options contains the URL to use for sending statistics.\n * @returns {Promise<void>}\n * @throws {Error}\n * @since 5.4.0\n */\n setStatsUrl(options: StatsUrl): Promise<void>;\n\n /**\n * Set the channelUrl for the app, this will be used to set the channel.\n *\n * @param options contains the URL to use for setting the channel.\n * @returns {Promise<void>}\n * @throws {Error}\n * @since 5.4.0\n */\n setChannelUrl(options: ChannelUrl): Promise<void>;\n\n /**\n * Download a new bundle from the provided URL, it should be a zip file, with files inside or with a unique id inside with all your files\n *\n * @example const bundle = await CapacitorUpdater.download({ url: `https://example.com/versions/${version}/dist.zip`, version });\n * @returns {Promise<BundleInfo>} The {@link BundleInfo} for the specified bundle.\n * @param options The {@link DownloadOptions} for downloading a new bundle zip.\n */\n download(options: DownloadOptions): Promise<BundleInfo>;\n\n /**\n * Set the next bundle to be used when the app is reloaded.\n *\n * @param options Contains the ID of the next Bundle to set on next app launch. {@link BundleInfo.id}\n * @returns {Promise<BundleInfo>} The {@link BundleInfo} for the specified bundle id.\n * @throws {Error} When there is no index.html file inside the bundle folder.\n */\n next(options: BundleId): Promise<BundleInfo>;\n\n /**\n * Set the current bundle and immediately reloads the app.\n *\n * @param options A {@link BundleId} object containing the new bundle id to set as current.\n * @returns {Promise<void>}\n * @throws {Error} When there are is no index.html file inside the bundle folder.\n */\n set(options: BundleId): Promise<void>;\n\n /**\n * Deletes the specified bundle from the native app storage. Use with {@link list} to get the stored Bundle IDs.\n *\n * @param options A {@link BundleId} object containing the ID of a bundle to delete (note, this is the bundle id, NOT the version name)\n * @returns {Promise<void>} When the bundle is deleted\n * @throws {Error}\n */\n delete(options: BundleId): Promise<void>;\n\n /**\n * Get all locally downloaded bundles in your app\n *\n * @returns {Promise<BundleListResult>} A Promise containing the {@link BundleListResult.bundles}\n * @param options The {@link ListOptions} for listing bundles\n * @throws {Error}\n */\n list(options?: ListOptions): Promise<BundleListResult>;\n\n /**\n * Reset the app to the `builtin` bundle (the one sent to Apple App Store / Google Play Store ) or the last successfully loaded bundle.\n *\n * @param options Containing {@link ResetOptions.toLastSuccessful}, `true` resets to the builtin bundle and `false` will reset to the last successfully loaded bundle.\n * @returns {Promise<void>}\n * @throws {Error}\n */\n reset(options?: ResetOptions): Promise<void>;\n\n /**\n * Get the current bundle, if none are set it returns `builtin`. currentNative is the original bundle installed on the device\n *\n * @returns {Promise<CurrentBundleResult>} A Promise evaluating to the {@link CurrentBundleResult}\n * @throws {Error}\n */\n current(): Promise<CurrentBundleResult>;\n\n /**\n * Reload the view\n *\n * @returns {Promise<void>} A Promise which is resolved when the view is reloaded\n * @throws {Error}\n */\n reload(): Promise<void>;\n\n /**\n * Sets a {@link DelayCondition} array containing conditions that the Plugin will use to delay the update.\n * After all conditions are met, the update process will run start again as usual, so update will be installed after a backgrounding or killing the app.\n * For the `date` kind, the value should be an iso8601 date string.\n * For the `background` kind, the value should be a number in milliseconds.\n * For the `nativeVersion` kind, the value should be the version number.\n * For the `kill` kind, the value is not used.\n * The function has unconsistent behavior the option kill do trigger the update after the first kill and not after the next background like other options. This will be fixed in a future major release.\n *\n * @example\n * // Delay the update after the user kills the app or after a background of 300000 ms (5 minutes)\n * await CapacitorUpdater.setMultiDelay({ delayConditions: [{ kind: 'kill' }, { kind: 'background', value: '300000' }] })\n * @example\n * // Delay the update after the specific iso8601 date is expired\n * await CapacitorUpdater.setMultiDelay({ delayConditions: [{ kind: 'date', value: '2022-09-14T06:14:11.920Z' }] })\n * @example\n * // Delay the update after the first background (default behaviour without setting delay)\n * await CapacitorUpdater.setMultiDelay({ delayConditions: [{ kind: 'background' }] })\n * @param options Containing the {@link MultiDelayConditions} array of conditions to set\n * @returns {Promise<void>}\n * @throws {Error}\n * @since 4.3.0\n */\n setMultiDelay(options: MultiDelayConditions): Promise<void>;\n\n /**\n * Cancels a {@link DelayCondition} to process an update immediately.\n *\n * @returns {Promise<void>}\n * @throws {Error}\n * @since 4.0.0\n */\n cancelDelay(): Promise<void>;\n\n /**\n * Get Latest bundle available from update Url\n *\n * @returns {Promise<LatestVersion>} A Promise resolved when url is loaded\n * @throws {Error}\n * @since 4.0.0\n */\n getLatest(options?: GetLatestOptions): Promise<LatestVersion>;\n\n /**\n * Sets the channel for this device. The channel has to allow for self assignment for this to work.\n * Do not use this method to set the channel at boot.\n * This method is to set the channel after the app is ready, and user interacted.\n * If you want to set the channel at boot, use the {@link PluginsConfig} to set the default channel.\n * This methods send to Capgo backend a request to link the device ID to the channel. Capgo can accept or refuse depending of the setting of your channel.\n *\n *\n *\n * @param options Is the {@link SetChannelOptions} channel to set\n * @returns {Promise<ChannelRes>} A Promise which is resolved when the new channel is set\n * @throws {Error}\n * @since 4.7.0\n */\n setChannel(options: SetChannelOptions): Promise<ChannelRes>;\n\n /**\n * Unset the channel for this device. The device will then return to the default channel\n *\n * @returns {Promise<ChannelRes>} A Promise resolved when channel is set\n * @throws {Error}\n * @since 4.7.0\n */\n unsetChannel(options: UnsetChannelOptions): Promise<void>;\n\n /**\n * Get the channel for this device\n *\n * @returns {Promise<ChannelRes>} A Promise that resolves with the channel info\n * @throws {Error}\n * @since 4.8.0\n */\n getChannel(): Promise<GetChannelRes>;\n\n /**\n * List all channels available for this device that allow self-assignment\n *\n * @returns {Promise<ListChannelsResult>} A Promise that resolves with the available channels\n * @throws {Error}\n * @since 7.5.0\n */\n listChannels(): Promise<ListChannelsResult>;\n\n /**\n * Set a custom ID for this device\n *\n * @param options is the {@link SetCustomIdOptions} customId to set\n * @returns {Promise<void>} an Promise resolved instantly\n * @throws {Error}\n * @since 4.9.0\n */\n setCustomId(options: SetCustomIdOptions): Promise<void>;\n\n /**\n * Get the native app version or the builtin version if set in config\n *\n * @returns {Promise<BuiltinVersion>} A Promise with version for this device\n * @since 5.2.0\n */\n getBuiltinVersion(): Promise<BuiltinVersion>;\n\n /**\n * Get unique ID used to identify device (sent to auto update server)\n *\n * @returns {Promise<DeviceId>} A Promise with id for this device\n * @throws {Error}\n */\n getDeviceId(): Promise<DeviceId>;\n\n /**\n * Get the native Capacitor Updater plugin version (sent to auto update server)\n *\n * @returns {Promise<PluginVersion>} A Promise with Plugin version\n * @throws {Error}\n */\n getPluginVersion(): Promise<PluginVersion>;\n\n /**\n * Get the state of auto update config.\n *\n * @returns {Promise<AutoUpdateEnabled>} The status for auto update. Evaluates to `false` in manual mode.\n * @throws {Error}\n */\n isAutoUpdateEnabled(): Promise<AutoUpdateEnabled>;\n\n /**\n * Remove all listeners for this plugin.\n *\n * @since 1.0.0\n */\n removeAllListeners(): Promise<void>;\n\n /**\n * Listen for bundle download event in the App. Fires once a download has started, during downloading and when finished.\n * This will return you all download percent during the download\n *\n * @since 2.0.11\n */\n addListener(eventName: 'download', listenerFunc: (state: DownloadEvent) => void): Promise<PluginListenerHandle>;\n\n /**\n * Listen for no need to update event, useful when you want force check every time the app is launched\n *\n * @since 4.0.0\n */\n addListener(eventName: 'noNeedUpdate', listenerFunc: (state: NoNeedEvent) => void): Promise<PluginListenerHandle>;\n\n /**\n * Listen for available update event, useful when you want to force check every time the app is launched\n *\n * @since 4.0.0\n */\n addListener(\n eventName: 'updateAvailable',\n listenerFunc: (state: UpdateAvailableEvent) => void,\n ): Promise<PluginListenerHandle>;\n\n /**\n * Listen for downloadComplete events.\n *\n * @since 4.0.0\n */\n addListener(\n eventName: 'downloadComplete',\n listenerFunc: (state: DownloadCompleteEvent) => void,\n ): Promise<PluginListenerHandle>;\n\n /**\n * Listen for Major update event in the App, let you know when major update is blocked by setting disableAutoUpdateBreaking\n *\n * @since 2.3.0\n */\n addListener(\n eventName: 'majorAvailable',\n listenerFunc: (state: MajorAvailableEvent) => void,\n ): Promise<PluginListenerHandle>;\n\n /**\n * Listen for update fail event in the App, let you know when update has fail to install at next app start\n *\n * @since 2.3.0\n */\n addListener(\n eventName: 'updateFailed',\n listenerFunc: (state: UpdateFailedEvent) => void,\n ): Promise<PluginListenerHandle>;\n\n /**\n * Listen for download fail event in the App, let you know when a bundle download has failed\n *\n * @since 4.0.0\n */\n addListener(\n eventName: 'downloadFailed',\n listenerFunc: (state: DownloadFailedEvent) => void,\n ): Promise<PluginListenerHandle>;\n\n /**\n * Listen for reload event in the App, let you know when reload has happened\n *\n * @since 4.3.0\n */\n addListener(eventName: 'appReloaded', listenerFunc: () => void): Promise<PluginListenerHandle>;\n\n /**\n * Listen for app ready event in the App, let you know when app is ready to use\n *\n * @since 5.1.0\n */\n addListener(eventName: 'appReady', listenerFunc: (state: AppReadyEvent) => void): Promise<PluginListenerHandle>;\n\n /**\n * Get if auto update is available (not disabled by serverUrl).\n *\n * @returns {Promise<AutoUpdateAvailable>} The availability status for auto update. Evaluates to `false` when serverUrl is set.\n * @throws {Error}\n */\n isAutoUpdateAvailable(): Promise<AutoUpdateAvailable>;\n\n /**\n * Get the next bundle that will be used when the app reloads.\n * Returns null if no next bundle is set.\n *\n * @returns {Promise<BundleInfo | null>} A Promise that resolves with the next bundle information or null\n * @throws {Error}\n * @since 6.8.0\n */\n getNextBundle(): Promise<BundleInfo | null>;\n\n /**\n * Enable or disable the shake menu for debugging/testing purposes\n *\n * @param options Contains enabled boolean to enable or disable shake menu\n * @returns {Promise<void>}\n * @throws {Error}\n * @since 7.5.0\n */\n setShakeMenu(options: SetShakeMenuOptions): Promise<void>;\n\n /**\n * Get the current state of the shake menu\n *\n * @returns {Promise<ShakeMenuEnabled>} The current state of shake menu\n * @throws {Error}\n * @since 7.5.0\n */\n isShakeMenuEnabled(): Promise<ShakeMenuEnabled>;\n}\n\n/**\n * pending: The bundle is pending to be **SET** as the next bundle.\n * downloading: The bundle is being downloaded.\n * success: The bundle has been downloaded and is ready to be **SET** as the next bundle.\n * error: The bundle has failed to download.\n */\nexport type BundleStatus = 'success' | 'error' | 'pending' | 'downloading';\n\nexport type DelayUntilNext = 'background' | 'kill' | 'nativeVersion' | 'date';\n\nexport interface NoNeedEvent {\n /**\n * Current status of download, between 0 and 100.\n *\n * @since 4.0.0\n */\n bundle: BundleInfo;\n}\n\nexport interface UpdateAvailableEvent {\n /**\n * Current status of download, between 0 and 100.\n *\n * @since 4.0.0\n */\n bundle: BundleInfo;\n}\n\nexport interface ChannelRes {\n /**\n * Current status of set channel\n *\n * @since 4.7.0\n */\n status: string;\n error?: string;\n message?: string;\n}\n\nexport interface GetChannelRes {\n /**\n * Current status of get channel\n *\n * @since 4.8.0\n */\n channel?: string;\n error?: string;\n message?: string;\n status?: string;\n allowSet?: boolean;\n}\n\nexport interface ChannelInfo {\n /**\n * The channel ID\n *\n * @since 7.5.0\n */\n id: string;\n /**\n * The channel name\n *\n * @since 7.5.0\n */\n name: string;\n /**\n * Whether this is a public channel\n *\n * @since 7.5.0\n */\n public: boolean;\n /**\n * Whether devices can self-assign to this channel\n *\n * @since 7.5.0\n */\n allow_self_set: boolean;\n}\n\nexport interface ListChannelsResult {\n /**\n * List of available channels\n *\n * @since 7.5.0\n */\n channels: ChannelInfo[];\n}\n\nexport interface DownloadEvent {\n /**\n * Current status of download, between 0 and 100.\n *\n * @since 4.0.0\n */\n percent: number;\n bundle: BundleInfo;\n}\n\nexport interface MajorAvailableEvent {\n /**\n * Emit when a new major bundle is available.\n *\n * @since 4.0.0\n */\n version: string;\n}\n\nexport interface DownloadFailedEvent {\n /**\n * Emit when a download fail.\n *\n * @since 4.0.0\n */\n version: string;\n}\n\nexport interface DownloadCompleteEvent {\n /**\n * Emit when a new update is available.\n *\n * @since 4.0.0\n */\n bundle: BundleInfo;\n}\n\nexport interface UpdateFailedEvent {\n /**\n * Emit when a update failed to install.\n *\n * @since 4.0.0\n */\n bundle: BundleInfo;\n}\n\nexport interface AppReadyEvent {\n /**\n * Emitted when the app is ready to use.\n *\n * @since 5.2.0\n */\n bundle: BundleInfo;\n status: string;\n}\n\nexport interface ManifestEntry {\n file_name: string | null;\n file_hash: string | null;\n download_url: string | null;\n}\n\nexport interface LatestVersion {\n /**\n * Result of getLatest method\n *\n * @since 4.0.0\n */\n version: string;\n /**\n * @since 6\n */\n checksum?: string;\n major?: boolean;\n message?: string;\n sessionKey?: string;\n error?: string;\n old?: string;\n url?: string;\n /**\n * @since 6.1\n */\n manifest?: ManifestEntry[];\n}\n\nexport interface BundleInfo {\n id: string;\n version: string;\n downloaded: string;\n checksum: string;\n status: BundleStatus;\n}\n\nexport interface SetChannelOptions {\n channel: string;\n triggerAutoUpdate?: boolean;\n}\n\nexport interface UnsetChannelOptions {\n triggerAutoUpdate?: boolean;\n}\n\nexport interface SetCustomIdOptions {\n customId: string;\n}\n\nexport interface DelayCondition {\n /**\n * Set up delay conditions in setMultiDelay\n * @param value is useless for @param kind \"kill\", optional for \"background\" (default value: \"0\") and required for \"nativeVersion\" and \"date\"\n */\n kind: DelayUntilNext;\n value?: string;\n}\n\nexport interface GetLatestOptions {\n /**\n * The channel to get the latest version for\n * The channel must allow 'self_assign' for this to work\n * @since 6.8.0\n * @default undefined\n */\n channel?: string;\n}\n\nexport interface AppReadyResult {\n bundle: BundleInfo;\n}\n\nexport interface UpdateUrl {\n url: string;\n}\n\nexport interface StatsUrl {\n url: string;\n}\n\nexport interface ChannelUrl {\n url: string;\n}\n\n/**\n * This URL and versions are used to download the bundle from the server, If you use backend all information will be gived by the method getLatest.\n * If you don't use backend, you need to provide the URL and version of the bundle. Checksum and sessionKey are required if you encrypted the bundle with the CLI command encrypt, you should receive them as result of the command.\n */\nexport interface DownloadOptions {\n /**\n * The URL of the bundle zip file (e.g: dist.zip) to be downloaded. (This can be any URL. E.g: Amazon S3, a GitHub tag, any other place you've hosted your bundle.)\n */\n url: string;\n /**\n * The version code/name of this bundle/version\n */\n version: string;\n /**\n * The session key for the update, when the bundle is encrypted with a session key\n * @since 4.0.0\n * @default undefined\n */\n sessionKey?: string;\n /**\n * The checksum for the update, it should be in sha256 and encrypted with private key if the bundle is encrypted\n * @since 4.0.0\n * @default undefined\n */\n checksum?: string;\n /**\n * The manifest for multi-file downloads\n * @since 6.1.0\n * @default undefined\n */\n manifest?: ManifestEntry[];\n}\n\nexport interface BundleId {\n id: string;\n}\n\nexport interface BundleListResult {\n bundles: BundleInfo[];\n}\n\nexport interface ResetOptions {\n toLastSuccessful: boolean;\n}\n\nexport interface ListOptions {\n /**\n * Whether to return the raw bundle list or the manifest. If true, the list will attempt to read the internal database instead of files on disk.\n * @since 6.14.0\n * @default false\n */\n raw?: boolean;\n}\n\nexport interface CurrentBundleResult {\n bundle: BundleInfo;\n native: string;\n}\n\nexport interface MultiDelayConditions {\n delayConditions: DelayCondition[];\n}\n\nexport interface BuiltinVersion {\n version: string;\n}\n\nexport interface DeviceId {\n deviceId: string;\n}\n\nexport interface PluginVersion {\n version: string;\n}\n\nexport interface AutoUpdateEnabled {\n enabled: boolean;\n}\n\nexport interface AutoUpdateAvailable {\n available: boolean;\n}\n\nexport interface SetShakeMenuOptions {\n enabled: boolean;\n}\n\nexport interface ShakeMenuEnabled {\n enabled: boolean;\n}\n"]}
1
+ {"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"AAAA;;;;GAIG","sourcesContent":["/*\n * This Source Code Form is subject to the terms of the Mozilla Public\n * License, v. 2.0. If a copy of the MPL was not distributed with this\n * file, You can obtain one at https://mozilla.org/MPL/2.0/.\n */\n\n/// <reference types=\"@capacitor/cli\" />\n\nimport type { PluginListenerHandle } from '@capacitor/core';\n\ndeclare module '@capacitor/cli' {\n export interface PluginsConfig {\n /**\n * CapacitorUpdater can be configured with these options:\n */\n CapacitorUpdater?: {\n /**\n * Configure the number of milliseconds the native plugin should wait before considering an update 'failed'.\n *\n * Only available for Android and iOS.\n *\n * @default 10000 // (10 seconds)\n * @example 1000 // (1 second)\n */\n appReadyTimeout?: number;\n /**\n * Configure the number of milliseconds the native plugin should wait before considering API timeout.\n *\n * Only available for Android and iOS.\n *\n * @default 20 // (20 second)\n * @example 10 // (10 second)\n */\n responseTimeout?: number;\n /**\n * Configure whether the plugin should use automatically delete failed bundles.\n *\n * Only available for Android and iOS.\n *\n * @default true\n * @example false\n */\n autoDeleteFailed?: boolean;\n\n /**\n * Configure whether the plugin should use automatically delete previous bundles after a successful update.\n *\n * Only available for Android and iOS.\n *\n * @default true\n * @example false\n */\n autoDeletePrevious?: boolean;\n\n /**\n * Configure whether the plugin should use Auto Update via an update server.\n *\n * Only available for Android and iOS.\n *\n * @default true\n * @example false\n */\n autoUpdate?: boolean;\n\n /**\n * Automatically delete previous downloaded bundles when a newer native app bundle is installed to the device.\n *\n * Only available for Android and iOS.\n *\n * @default true\n * @example false\n */\n resetWhenUpdate?: boolean;\n\n /**\n * Configure the URL / endpoint to which update checks are sent.\n *\n * Only available for Android and iOS.\n *\n * @default https://plugin.capgo.app/updates\n * @example https://example.com/api/auto_update\n */\n updateUrl?: string;\n\n /**\n * Configure the URL / endpoint for channel operations.\n *\n * Only available for Android and iOS.\n *\n * @default https://plugin.capgo.app/channel_self\n * @example https://example.com/api/channel\n */\n channelUrl?: string;\n\n /**\n * Configure the URL / endpoint to which update statistics are sent.\n *\n * Only available for Android and iOS. Set to \"\" to disable stats reporting.\n *\n * @default https://plugin.capgo.app/stats\n * @example https://example.com/api/stats\n */\n statsUrl?: string;\n /**\n * Configure the public key for end to end live update encryption Version 2\n *\n * Only available for Android and iOS.\n *\n * @default undefined\n * @since 6.2.0\n */\n publicKey?: string;\n\n /**\n * Configure the current version of the app. This will be used for the first update request.\n * If not set, the plugin will get the version from the native code.\n *\n * Only available for Android and iOS.\n *\n * @default undefined\n * @since 4.17.48\n */\n version?: string;\n /**\n * 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 *\n * Only available for Android and iOS.\n *\n * @default false\n * @since 5.1.0\n */\n directUpdate?: boolean | 'atInstall' | 'always';\n\n /**\n * 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.\n * This removes the need to manually listen for appReady events and call SplashScreen.hide().\n * Only works when directUpdate is set to \"atInstall\", \"always\", or true.\n * Requires the @capacitor/splash-screen plugin to be installed and configured with launchAutoHide: false.\n *\n * Only available for Android and iOS.\n *\n * @default false\n * @since 7.6.0\n */\n autoSplashscreen?: boolean;\n\n /**\n * Configure the delay period for period update check. the unit is in seconds.\n *\n * Only available for Android and iOS.\n * Cannot be less than 600 seconds (10 minutes).\n *\n * @default 600 // (10 minutes)\n */\n periodCheckDelay?: number;\n\n /**\n * Configure the CLI to use a local server for testing or self-hosted update server.\n *\n *\n * @default undefined\n * @since 4.17.48\n */\n localS3?: boolean;\n /**\n * Configure the CLI to use a local server for testing or self-hosted update server.\n *\n *\n * @default undefined\n * @since 4.17.48\n */\n localHost?: string;\n /**\n * Configure the CLI to use a local server for testing or self-hosted update server.\n *\n *\n * @default undefined\n * @since 4.17.48\n */\n localWebHost?: string;\n /**\n * Configure the CLI to use a local server for testing or self-hosted update server.\n *\n *\n * @default undefined\n * @since 4.17.48\n */\n localSupa?: string;\n /**\n * Configure the CLI to use a local server for testing.\n *\n *\n * @default undefined\n * @since 4.17.48\n */\n localSupaAnon?: string;\n /**\n * Configure the CLI to use a local api for testing.\n *\n *\n * @default undefined\n * @since 6.3.3\n */\n localApi?: string;\n /**\n * Configure the CLI to use a local file api for testing.\n *\n *\n * @default undefined\n * @since 6.3.3\n */\n localApiFiles?: string;\n /**\n * Allow the plugin to modify the updateUrl, statsUrl and channelUrl dynamically from the JavaScript side.\n *\n *\n * @default false\n * @since 5.4.0\n */\n allowModifyUrl?: boolean;\n\n /**\n * Set the default channel for the app in the config. Case sensitive.\n * This will setting will override the default channel set in the cloud, but will still respect overrides made in the cloud.\n *\n *\n * @default undefined\n * @since 5.5.0\n */\n defaultChannel?: string;\n /**\n * Configure the app id for the app in the config.\n *\n * @default undefined\n * @since 6.0.0\n */\n appId?: string;\n\n /**\n * Configure the plugin to keep the URL path after a reload.\n * WARNING: When a reload is triggered, 'window.history' will be cleared.\n *\n * @default false\n * @since 6.8.0\n */\n keepUrlPathAfterReload?: boolean;\n /**\n * 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\n *\n * @default false\n * @since 7.3.0\n */\n disableJSLogging?: boolean;\n /**\n * Enable shake gesture to show update menu for debugging/testing purposes\n *\n * @default false\n * @since 7.5.0\n */\n shakeMenu?: boolean;\n };\n }\n}\n\nexport interface CapacitorUpdaterPlugin {\n /**\n * Notify Capacitor Updater that the current bundle is working (a rollback will occur if this method is not called on every app launch)\n * By default this method should be called in the first 10 sec after app launch, otherwise a rollback will occur.\n * Change this behaviour with {@link appReadyTimeout}\n *\n * @returns {Promise<AppReadyResult>} an Promise resolved directly\n * @throws {Error}\n */\n notifyAppReady(): Promise<AppReadyResult>;\n\n /**\n * Set the updateUrl for the app, this will be used to check for updates.\n *\n * @param options contains the URL to use for checking for updates.\n * @returns {Promise<void>}\n * @throws {Error}\n * @since 5.4.0\n */\n setUpdateUrl(options: UpdateUrl): Promise<void>;\n\n /**\n * Set the statsUrl for the app, this will be used to send statistics. Passing an empty string will disable statistics gathering.\n *\n * @param options contains the URL to use for sending statistics.\n * @returns {Promise<void>}\n * @throws {Error}\n * @since 5.4.0\n */\n setStatsUrl(options: StatsUrl): Promise<void>;\n\n /**\n * Set the channelUrl for the app, this will be used to set the channel.\n *\n * @param options contains the URL to use for setting the channel.\n * @returns {Promise<void>}\n * @throws {Error}\n * @since 5.4.0\n */\n setChannelUrl(options: ChannelUrl): Promise<void>;\n\n /**\n * Download a new bundle from the provided URL, it should be a zip file, with files inside or with a unique id inside with all your files\n *\n * @example const bundle = await CapacitorUpdater.download({ url: `https://example.com/versions/${version}/dist.zip`, version });\n * @returns {Promise<BundleInfo>} The {@link BundleInfo} for the specified bundle.\n * @param options The {@link DownloadOptions} for downloading a new bundle zip.\n */\n download(options: DownloadOptions): Promise<BundleInfo>;\n\n /**\n * Set the next bundle to be used when the app is reloaded.\n *\n * @param options Contains the ID of the next Bundle to set on next app launch. {@link BundleInfo.id}\n * @returns {Promise<BundleInfo>} The {@link BundleInfo} for the specified bundle id.\n * @throws {Error} When there is no index.html file inside the bundle folder.\n */\n next(options: BundleId): Promise<BundleInfo>;\n\n /**\n * Set the current bundle and immediately reloads the app.\n *\n * @param options A {@link BundleId} object containing the new bundle id to set as current.\n * @returns {Promise<void>}\n * @throws {Error} When there are is no index.html file inside the bundle folder.\n */\n set(options: BundleId): Promise<void>;\n\n /**\n * Deletes the specified bundle from the native app storage. Use with {@link list} to get the stored Bundle IDs.\n *\n * @param options A {@link BundleId} object containing the ID of a bundle to delete (note, this is the bundle id, NOT the version name)\n * @returns {Promise<void>} When the bundle is deleted\n * @throws {Error}\n */\n delete(options: BundleId): Promise<void>;\n\n /**\n * Get all locally downloaded bundles in your app\n *\n * @returns {Promise<BundleListResult>} A Promise containing the {@link BundleListResult.bundles}\n * @param options The {@link ListOptions} for listing bundles\n * @throws {Error}\n */\n list(options?: ListOptions): Promise<BundleListResult>;\n\n /**\n * Reset the app to the `builtin` bundle (the one sent to Apple App Store / Google Play Store ) or the last successfully loaded bundle.\n *\n * @param options Containing {@link ResetOptions.toLastSuccessful}, `true` resets to the builtin bundle and `false` will reset to the last successfully loaded bundle.\n * @returns {Promise<void>}\n * @throws {Error}\n */\n reset(options?: ResetOptions): Promise<void>;\n\n /**\n * Get the current bundle, if none are set it returns `builtin`. currentNative is the original bundle installed on the device\n *\n * @returns {Promise<CurrentBundleResult>} A Promise evaluating to the {@link CurrentBundleResult}\n * @throws {Error}\n */\n current(): Promise<CurrentBundleResult>;\n\n /**\n * Reload the view\n *\n * @returns {Promise<void>} A Promise which is resolved when the view is reloaded\n * @throws {Error}\n */\n reload(): Promise<void>;\n\n /**\n * Sets a {@link DelayCondition} array containing conditions that the Plugin will use to delay the update.\n * After all conditions are met, the update process will run start again as usual, so update will be installed after a backgrounding or killing the app.\n * For the `date` kind, the value should be an iso8601 date string.\n * For the `background` kind, the value should be a number in milliseconds.\n * For the `nativeVersion` kind, the value should be the version number.\n * For the `kill` kind, the value is not used.\n * The function has unconsistent behavior the option kill do trigger the update after the first kill and not after the next background like other options. This will be fixed in a future major release.\n *\n * @example\n * // Delay the update after the user kills the app or after a background of 300000 ms (5 minutes)\n * await CapacitorUpdater.setMultiDelay({ delayConditions: [{ kind: 'kill' }, { kind: 'background', value: '300000' }] })\n * @example\n * // Delay the update after the specific iso8601 date is expired\n * await CapacitorUpdater.setMultiDelay({ delayConditions: [{ kind: 'date', value: '2022-09-14T06:14:11.920Z' }] })\n * @example\n * // Delay the update after the first background (default behaviour without setting delay)\n * await CapacitorUpdater.setMultiDelay({ delayConditions: [{ kind: 'background' }] })\n * @param options Containing the {@link MultiDelayConditions} array of conditions to set\n * @returns {Promise<void>}\n * @throws {Error}\n * @since 4.3.0\n */\n setMultiDelay(options: MultiDelayConditions): Promise<void>;\n\n /**\n * Cancels a {@link DelayCondition} to process an update immediately.\n *\n * @returns {Promise<void>}\n * @throws {Error}\n * @since 4.0.0\n */\n cancelDelay(): Promise<void>;\n\n /**\n * Get Latest bundle available from update Url\n *\n * @returns {Promise<LatestVersion>} A Promise resolved when url is loaded\n * @throws {Error}\n * @since 4.0.0\n */\n getLatest(options?: GetLatestOptions): Promise<LatestVersion>;\n\n /**\n * Sets the channel for this device. The channel has to allow for self assignment for this to work.\n * Do not use this method to set the channel at boot.\n * This method is to set the channel after the app is ready, and user interacted.\n * If you want to set the channel at boot, use the {@link PluginsConfig} to set the default channel.\n * This methods send to Capgo backend a request to link the device ID to the channel. Capgo can accept or refuse depending of the setting of your channel.\n *\n *\n *\n * @param options Is the {@link SetChannelOptions} channel to set\n * @returns {Promise<ChannelRes>} A Promise which is resolved when the new channel is set\n * @throws {Error}\n * @since 4.7.0\n */\n setChannel(options: SetChannelOptions): Promise<ChannelRes>;\n\n /**\n * Unset the channel for this device. The device will then return to the default channel\n *\n * @returns {Promise<ChannelRes>} A Promise resolved when channel is set\n * @throws {Error}\n * @since 4.7.0\n */\n unsetChannel(options: UnsetChannelOptions): Promise<void>;\n\n /**\n * Get the channel for this device\n *\n * @returns {Promise<ChannelRes>} A Promise that resolves with the channel info\n * @throws {Error}\n * @since 4.8.0\n */\n getChannel(): Promise<GetChannelRes>;\n\n /**\n * List all channels available for this device that allow self-assignment\n *\n * @returns {Promise<ListChannelsResult>} A Promise that resolves with the available channels\n * @throws {Error}\n * @since 7.5.0\n */\n listChannels(): Promise<ListChannelsResult>;\n\n /**\n * Set a custom ID for this device\n *\n * @param options is the {@link SetCustomIdOptions} customId to set\n * @returns {Promise<void>} an Promise resolved instantly\n * @throws {Error}\n * @since 4.9.0\n */\n setCustomId(options: SetCustomIdOptions): Promise<void>;\n\n /**\n * Get the native app version or the builtin version if set in config\n *\n * @returns {Promise<BuiltinVersion>} A Promise with version for this device\n * @since 5.2.0\n */\n getBuiltinVersion(): Promise<BuiltinVersion>;\n\n /**\n * Get unique ID used to identify device (sent to auto update server)\n *\n * @returns {Promise<DeviceId>} A Promise with id for this device\n * @throws {Error}\n */\n getDeviceId(): Promise<DeviceId>;\n\n /**\n * Get the native Capacitor Updater plugin version (sent to auto update server)\n *\n * @returns {Promise<PluginVersion>} A Promise with Plugin version\n * @throws {Error}\n */\n getPluginVersion(): Promise<PluginVersion>;\n\n /**\n * Get the state of auto update config.\n *\n * @returns {Promise<AutoUpdateEnabled>} The status for auto update. Evaluates to `false` in manual mode.\n * @throws {Error}\n */\n isAutoUpdateEnabled(): Promise<AutoUpdateEnabled>;\n\n /**\n * Remove all listeners for this plugin.\n *\n * @since 1.0.0\n */\n removeAllListeners(): Promise<void>;\n\n /**\n * Listen for bundle download event in the App. Fires once a download has started, during downloading and when finished.\n * This will return you all download percent during the download\n *\n * @since 2.0.11\n */\n addListener(eventName: 'download', listenerFunc: (state: DownloadEvent) => void): Promise<PluginListenerHandle>;\n\n /**\n * Listen for no need to update event, useful when you want force check every time the app is launched\n *\n * @since 4.0.0\n */\n addListener(eventName: 'noNeedUpdate', listenerFunc: (state: NoNeedEvent) => void): Promise<PluginListenerHandle>;\n\n /**\n * Listen for available update event, useful when you want to force check every time the app is launched\n *\n * @since 4.0.0\n */\n addListener(\n eventName: 'updateAvailable',\n listenerFunc: (state: UpdateAvailableEvent) => void,\n ): Promise<PluginListenerHandle>;\n\n /**\n * Listen for downloadComplete events.\n *\n * @since 4.0.0\n */\n addListener(\n eventName: 'downloadComplete',\n listenerFunc: (state: DownloadCompleteEvent) => void,\n ): Promise<PluginListenerHandle>;\n\n /**\n * Listen for Major update event in the App, let you know when major update is blocked by setting disableAutoUpdateBreaking\n *\n * @since 2.3.0\n */\n addListener(\n eventName: 'majorAvailable',\n listenerFunc: (state: MajorAvailableEvent) => void,\n ): Promise<PluginListenerHandle>;\n\n /**\n * Listen for update fail event in the App, let you know when update has fail to install at next app start\n *\n * @since 2.3.0\n */\n addListener(\n eventName: 'updateFailed',\n listenerFunc: (state: UpdateFailedEvent) => void,\n ): Promise<PluginListenerHandle>;\n\n /**\n * Listen for download fail event in the App, let you know when a bundle download has failed\n *\n * @since 4.0.0\n */\n addListener(\n eventName: 'downloadFailed',\n listenerFunc: (state: DownloadFailedEvent) => void,\n ): Promise<PluginListenerHandle>;\n\n /**\n * Listen for reload event in the App, let you know when reload has happened\n *\n * @since 4.3.0\n */\n addListener(eventName: 'appReloaded', listenerFunc: () => void): Promise<PluginListenerHandle>;\n\n /**\n * Listen for app ready event in the App, let you know when app is ready to use\n *\n * @since 5.1.0\n */\n addListener(eventName: 'appReady', listenerFunc: (state: AppReadyEvent) => void): Promise<PluginListenerHandle>;\n\n /**\n * Get if auto update is available (not disabled by serverUrl).\n *\n * @returns {Promise<AutoUpdateAvailable>} The availability status for auto update. Evaluates to `false` when serverUrl is set.\n * @throws {Error}\n */\n isAutoUpdateAvailable(): Promise<AutoUpdateAvailable>;\n\n /**\n * Get the next bundle that will be used when the app reloads.\n * Returns null if no next bundle is set.\n *\n * @returns {Promise<BundleInfo | null>} A Promise that resolves with the next bundle information or null\n * @throws {Error}\n * @since 6.8.0\n */\n getNextBundle(): Promise<BundleInfo | null>;\n\n /**\n * Enable or disable the shake menu for debugging/testing purposes\n *\n * @param options Contains enabled boolean to enable or disable shake menu\n * @returns {Promise<void>}\n * @throws {Error}\n * @since 7.5.0\n */\n setShakeMenu(options: SetShakeMenuOptions): Promise<void>;\n\n /**\n * Get the current state of the shake menu\n *\n * @returns {Promise<ShakeMenuEnabled>} The current state of shake menu\n * @throws {Error}\n * @since 7.5.0\n */\n isShakeMenuEnabled(): Promise<ShakeMenuEnabled>;\n}\n\n/**\n * pending: The bundle is pending to be **SET** as the next bundle.\n * downloading: The bundle is being downloaded.\n * success: The bundle has been downloaded and is ready to be **SET** as the next bundle.\n * error: The bundle has failed to download.\n */\nexport type BundleStatus = 'success' | 'error' | 'pending' | 'downloading';\n\nexport type DelayUntilNext = 'background' | 'kill' | 'nativeVersion' | 'date';\n\nexport interface NoNeedEvent {\n /**\n * Current status of download, between 0 and 100.\n *\n * @since 4.0.0\n */\n bundle: BundleInfo;\n}\n\nexport interface UpdateAvailableEvent {\n /**\n * Current status of download, between 0 and 100.\n *\n * @since 4.0.0\n */\n bundle: BundleInfo;\n}\n\nexport interface ChannelRes {\n /**\n * Current status of set channel\n *\n * @since 4.7.0\n */\n status: string;\n error?: string;\n message?: string;\n}\n\nexport interface GetChannelRes {\n /**\n * Current status of get channel\n *\n * @since 4.8.0\n */\n channel?: string;\n error?: string;\n message?: string;\n status?: string;\n allowSet?: boolean;\n}\n\nexport interface ChannelInfo {\n /**\n * The channel ID\n *\n * @since 7.5.0\n */\n id: string;\n /**\n * The channel name\n *\n * @since 7.5.0\n */\n name: string;\n /**\n * Whether this is a public channel\n *\n * @since 7.5.0\n */\n public: boolean;\n /**\n * Whether devices can self-assign to this channel\n *\n * @since 7.5.0\n */\n allow_self_set: boolean;\n}\n\nexport interface ListChannelsResult {\n /**\n * List of available channels\n *\n * @since 7.5.0\n */\n channels: ChannelInfo[];\n}\n\nexport interface DownloadEvent {\n /**\n * Current status of download, between 0 and 100.\n *\n * @since 4.0.0\n */\n percent: number;\n bundle: BundleInfo;\n}\n\nexport interface MajorAvailableEvent {\n /**\n * Emit when a new major bundle is available.\n *\n * @since 4.0.0\n */\n version: string;\n}\n\nexport interface DownloadFailedEvent {\n /**\n * Emit when a download fail.\n *\n * @since 4.0.0\n */\n version: string;\n}\n\nexport interface DownloadCompleteEvent {\n /**\n * Emit when a new update is available.\n *\n * @since 4.0.0\n */\n bundle: BundleInfo;\n}\n\nexport interface UpdateFailedEvent {\n /**\n * Emit when a update failed to install.\n *\n * @since 4.0.0\n */\n bundle: BundleInfo;\n}\n\nexport interface AppReadyEvent {\n /**\n * Emitted when the app is ready to use.\n *\n * @since 5.2.0\n */\n bundle: BundleInfo;\n status: string;\n}\n\nexport interface ManifestEntry {\n file_name: string | null;\n file_hash: string | null;\n download_url: string | null;\n}\n\nexport interface LatestVersion {\n /**\n * Result of getLatest method\n *\n * @since 4.0.0\n */\n version: string;\n /**\n * @since 6\n */\n checksum?: string;\n major?: boolean;\n message?: string;\n sessionKey?: string;\n error?: string;\n old?: string;\n url?: string;\n /**\n * @since 6.1\n */\n manifest?: ManifestEntry[];\n}\n\nexport interface BundleInfo {\n id: string;\n version: string;\n downloaded: string;\n checksum: string;\n status: BundleStatus;\n}\n\nexport interface SetChannelOptions {\n channel: string;\n triggerAutoUpdate?: boolean;\n}\n\nexport interface UnsetChannelOptions {\n triggerAutoUpdate?: boolean;\n}\n\nexport interface SetCustomIdOptions {\n customId: string;\n}\n\nexport interface DelayCondition {\n /**\n * Set up delay conditions in setMultiDelay\n * @param value is useless for @param kind \"kill\", optional for \"background\" (default value: \"0\") and required for \"nativeVersion\" and \"date\"\n */\n kind: DelayUntilNext;\n value?: string;\n}\n\nexport interface GetLatestOptions {\n /**\n * The channel to get the latest version for\n * The channel must allow 'self_assign' for this to work\n * @since 6.8.0\n * @default undefined\n */\n channel?: string;\n}\n\nexport interface AppReadyResult {\n bundle: BundleInfo;\n}\n\nexport interface UpdateUrl {\n url: string;\n}\n\nexport interface StatsUrl {\n url: string;\n}\n\nexport interface ChannelUrl {\n url: string;\n}\n\n/**\n * This URL and versions are used to download the bundle from the server, If you use backend all information will be gived by the method getLatest.\n * If you don't use backend, you need to provide the URL and version of the bundle. Checksum and sessionKey are required if you encrypted the bundle with the CLI command encrypt, you should receive them as result of the command.\n */\nexport interface DownloadOptions {\n /**\n * The URL of the bundle zip file (e.g: dist.zip) to be downloaded. (This can be any URL. E.g: Amazon S3, a GitHub tag, any other place you've hosted your bundle.)\n */\n url: string;\n /**\n * The version code/name of this bundle/version\n */\n version: string;\n /**\n * The session key for the update, when the bundle is encrypted with a session key\n * @since 4.0.0\n * @default undefined\n */\n sessionKey?: string;\n /**\n * The checksum for the update, it should be in sha256 and encrypted with private key if the bundle is encrypted\n * @since 4.0.0\n * @default undefined\n */\n checksum?: string;\n /**\n * The manifest for multi-file downloads\n * @since 6.1.0\n * @default undefined\n */\n manifest?: ManifestEntry[];\n}\n\nexport interface BundleId {\n id: string;\n}\n\nexport interface BundleListResult {\n bundles: BundleInfo[];\n}\n\nexport interface ResetOptions {\n toLastSuccessful: boolean;\n}\n\nexport interface ListOptions {\n /**\n * Whether to return the raw bundle list or the manifest. If true, the list will attempt to read the internal database instead of files on disk.\n * @since 6.14.0\n * @default false\n */\n raw?: boolean;\n}\n\nexport interface CurrentBundleResult {\n bundle: BundleInfo;\n native: string;\n}\n\nexport interface MultiDelayConditions {\n delayConditions: DelayCondition[];\n}\n\nexport interface BuiltinVersion {\n version: string;\n}\n\nexport interface DeviceId {\n deviceId: string;\n}\n\nexport interface PluginVersion {\n version: string;\n}\n\nexport interface AutoUpdateEnabled {\n enabled: boolean;\n}\n\nexport interface AutoUpdateAvailable {\n available: boolean;\n}\n\nexport interface SetShakeMenuOptions {\n enabled: boolean;\n}\n\nexport interface ShakeMenuEnabled {\n enabled: boolean;\n}\n"]}
@@ -50,7 +50,7 @@ public class CapacitorUpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
50
50
  CAPPluginMethod(name: "isShakeMenuEnabled", returnType: CAPPluginReturnPromise)
51
51
  ]
52
52
  public var implementation = CapgoUpdater()
53
- private let PLUGIN_VERSION: String = "7.5.1"
53
+ private let PLUGIN_VERSION: String = "7.7.0"
54
54
  static let updateUrlDefault = "https://plugin.capgo.app/updates"
55
55
  static let statsUrlDefault = "https://plugin.capgo.app/stats"
56
56
  static let channelUrlDefault = "https://plugin.capgo.app/channel_self"
@@ -64,6 +64,9 @@ public class CapacitorUpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
64
64
  private var appReadyCheck: DispatchWorkItem?
65
65
  private var resetWhenUpdate = true
66
66
  private var directUpdate = false
67
+ private var directUpdateMode: String = "false"
68
+ private var wasRecentlyInstalledOrUpdated = false
69
+ private var autoSplashscreen = false
67
70
  private var autoDeleteFailed = false
68
71
  private var autoDeletePrevious = false
69
72
  private var keepUrlPathAfterReload = false
@@ -109,7 +112,23 @@ public class CapacitorUpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
109
112
  autoDeleteFailed = getConfig().getBoolean("autoDeleteFailed", true)
110
113
  autoDeletePrevious = getConfig().getBoolean("autoDeletePrevious", true)
111
114
  keepUrlPathAfterReload = getConfig().getBoolean("keepUrlPathAfterReload", false)
112
- directUpdate = getConfig().getBoolean("directUpdate", false)
115
+
116
+ // Handle directUpdate configuration - support string values and backward compatibility
117
+ if let directUpdateString = getConfig().getString("directUpdate") {
118
+ directUpdateMode = directUpdateString
119
+ directUpdate = directUpdateString == "always" || directUpdateString == "atInstall"
120
+ } else {
121
+ let directUpdateBool = getConfig().getBoolean("directUpdate", false)
122
+ if directUpdateBool {
123
+ directUpdateMode = "always" // backward compatibility: true = always
124
+ directUpdate = true
125
+ } else {
126
+ directUpdateMode = "false"
127
+ directUpdate = false
128
+ }
129
+ }
130
+
131
+ autoSplashscreen = getConfig().getBoolean("autoSplashscreen", false)
113
132
  updateUrl = getConfig().getString("updateUrl", CapacitorUpdaterPlugin.updateUrlDefault)!
114
133
  autoUpdate = getConfig().getBoolean("autoUpdate", true)
115
134
  appReadyTimeout = getConfig().getInt("appReadyTimeout", 10000)
@@ -148,6 +167,9 @@ public class CapacitorUpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
148
167
  implementation.defaultChannel = getConfig().getString("defaultChannel", "")!
149
168
  self.implementation.autoReset()
150
169
 
170
+ // Check if app was recently installed/updated BEFORE cleanupObsoleteVersions updates LatestVersionNative
171
+ self.wasRecentlyInstalledOrUpdated = self.checkIfRecentlyInstalledOrUpdated()
172
+
151
173
  if resetWhenUpdate {
152
174
  self.cleanupObsoleteVersions()
153
175
  }
@@ -749,6 +771,75 @@ public class CapacitorUpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
749
771
  DispatchQueue.global().async {
750
772
  self.semaphoreWait(waitTime: self.appReadyTimeout)
751
773
  self.notifyListeners("appReady", data: ["bundle": current.toJSON(), "status": msg])
774
+
775
+ // Auto hide splashscreen if enabled
776
+ if self.autoSplashscreen && self.shouldUseDirectUpdate() {
777
+ self.hideSplashscreen()
778
+ }
779
+ }
780
+ }
781
+
782
+ private func hideSplashscreen() {
783
+ DispatchQueue.main.async {
784
+ guard let bridge = self.bridge else {
785
+ self.logger.warn("Bridge not available for hiding splashscreen")
786
+ return
787
+ }
788
+
789
+ // Create a plugin call for the hide method
790
+ let call = CAPPluginCall(callbackId: "autoHideSplashscreen", options: [:], success: { (_, _) in
791
+ self.logger.info("Splashscreen hidden automatically")
792
+ }, error: { (_) in
793
+ self.logger.error("Failed to auto-hide splashscreen")
794
+ })
795
+
796
+ // Try to call the SplashScreen hide method directly through the bridge
797
+ if let splashScreenPlugin = bridge.plugin(withName: "SplashScreen") {
798
+ // Use runtime method invocation to call hide method
799
+ let selector = NSSelectorFromString("hide:")
800
+ if splashScreenPlugin.responds(to: selector) {
801
+ _ = splashScreenPlugin.perform(selector, with: call)
802
+ self.logger.info("Called SplashScreen hide method")
803
+ } else {
804
+ self.logger.warn("SplashScreen plugin does not respond to hide: method")
805
+ }
806
+ } else {
807
+ self.logger.warn("SplashScreen plugin not found")
808
+ }
809
+ }
810
+ }
811
+
812
+ private func checkIfRecentlyInstalledOrUpdated() -> Bool {
813
+ let userDefaults = UserDefaults.standard
814
+ let currentVersion = self.currentVersionNative.description
815
+ let lastKnownVersion = userDefaults.string(forKey: "LatestVersionNative") ?? "0.0.0"
816
+
817
+ if lastKnownVersion == "0.0.0" {
818
+ // First time running, consider it as recently installed
819
+ return true
820
+ } else if lastKnownVersion != currentVersion {
821
+ // Version changed, consider it as recently updated
822
+ return true
823
+ }
824
+
825
+ return false
826
+ }
827
+
828
+ private func shouldUseDirectUpdate() -> Bool {
829
+ switch directUpdateMode {
830
+ case "false":
831
+ return false
832
+ case "always":
833
+ return true
834
+ case "atInstall":
835
+ if self.wasRecentlyInstalledOrUpdated {
836
+ // Reset the flag after first use to prevent subsequent foreground events from using direct update
837
+ self.wasRecentlyInstalledOrUpdated = false
838
+ return true
839
+ }
840
+ return false
841
+ default:
842
+ return false
752
843
  }
753
844
  }
754
845
 
@@ -764,7 +855,8 @@ public class CapacitorUpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
764
855
  }
765
856
 
766
857
  func backgroundDownload() {
767
- let messageUpdate = self.directUpdate ? "Update will occur now." : "Update will occur next time app moves to background."
858
+ let shouldDirectUpdate = self.shouldUseDirectUpdate()
859
+ let messageUpdate = shouldDirectUpdate ? "Update will occur now." : "Update will occur next time app moves to background."
768
860
  guard let url = URL(string: self.updateUrl) else {
769
861
  logger.error("Error no url or wrong format")
770
862
  return
@@ -788,7 +880,7 @@ public class CapacitorUpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
788
880
  }
789
881
  if res.version == "builtin" {
790
882
  self.logger.info("Latest version is builtin")
791
- if self.directUpdate {
883
+ if shouldDirectUpdate {
792
884
  self.logger.info("Direct update to builtin version")
793
885
  _ = self._reset(toLastSuccessful: false)
794
886
  self.endBackGroundTaskWithNotif(msg: "Updated to builtin version", latestVersionName: res.version, current: self.implementation.getCurrentBundle(), error: false)
@@ -848,7 +940,7 @@ public class CapacitorUpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
848
940
  self.endBackGroundTaskWithNotif(msg: "Error checksum", latestVersionName: latestVersionName, current: current)
849
941
  return
850
942
  }
851
- if self.directUpdate {
943
+ if shouldDirectUpdate {
852
944
  let delayUpdatePreferences = UserDefaults.standard.string(forKey: DelayUpdateUtils.DELAY_CONDITION_PREFERENCES) ?? "[]"
853
945
  let delayConditionList: [DelayCondition] = self.fromJsonArr(json: delayUpdatePreferences).map { obj -> DelayCondition in
854
946
  let kind: String = obj.value(forKey: "kind") as! String
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capgo/capacitor-updater",
3
- "version": "7.5.1",
3
+ "version": "7.7.0",
4
4
  "license": "MPL-2.0",
5
5
  "description": "Live update for capacitor apps",
6
6
  "main": "dist/plugin.cjs.js",