@capgo/capacitor-updater 7.18.15 → 7.19.2
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 +37 -31
- package/android/src/main/java/ee/forgr/capacitor_updater/CapacitorUpdaterPlugin.java +190 -56
- package/android/src/main/java/ee/forgr/capacitor_updater/DelayUpdateUtils.java +5 -11
- package/dist/docs.json +32 -0
- package/dist/esm/definitions.d.ts +24 -0
- package/dist/esm/definitions.js.map +1 -1
- package/ios/Sources/CapacitorUpdaterPlugin/CapacitorUpdaterPlugin.swift +212 -49
- package/ios/Sources/CapacitorUpdaterPlugin/DelayUpdateUtils.swift +2 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -228,37 +228,39 @@ Capacitor Updater works by unzipping a compiled app bundle to the native device
|
|
|
228
228
|
|
|
229
229
|
CapacitorUpdater can be configured with these options:
|
|
230
230
|
|
|
231
|
-
| Prop
|
|
232
|
-
|
|
|
233
|
-
| **`appReadyTimeout`**
|
|
234
|
-
| **`responseTimeout`**
|
|
235
|
-
| **`autoDeleteFailed`**
|
|
236
|
-
| **`autoDeletePrevious`**
|
|
237
|
-
| **`autoUpdate`**
|
|
238
|
-
| **`resetWhenUpdate`**
|
|
239
|
-
| **`updateUrl`**
|
|
240
|
-
| **`channelUrl`**
|
|
241
|
-
| **`statsUrl`**
|
|
242
|
-
| **`publicKey`**
|
|
243
|
-
| **`version`**
|
|
244
|
-
| **`directUpdate`**
|
|
245
|
-
| **`autoSplashscreen`**
|
|
246
|
-
| **`
|
|
247
|
-
| **`
|
|
248
|
-
| **`
|
|
249
|
-
| **`
|
|
250
|
-
| **`
|
|
251
|
-
| **`
|
|
252
|
-
| **`
|
|
253
|
-
| **`
|
|
254
|
-
| **`
|
|
255
|
-
| **`
|
|
256
|
-
| **`
|
|
257
|
-
| **`
|
|
258
|
-
| **`
|
|
259
|
-
| **`
|
|
260
|
-
| **`
|
|
261
|
-
| **`
|
|
231
|
+
| Prop | Type | Description | Default | Since |
|
|
232
|
+
| ----------------------------- | ----------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- | ------- |
|
|
233
|
+
| **`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> | |
|
|
234
|
+
| **`responseTimeout`** | <code>number</code> | Configure the number of seconds the native plugin should wait before considering API timeout. Only available for Android and iOS. | <code>20 // (20 second)</code> | |
|
|
235
|
+
| **`autoDeleteFailed`** | <code>boolean</code> | Configure whether the plugin should use automatically delete failed bundles. Only available for Android and iOS. | <code>true</code> | |
|
|
236
|
+
| **`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> | |
|
|
237
|
+
| **`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> | |
|
|
238
|
+
| **`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> | |
|
|
239
|
+
| **`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> | |
|
|
240
|
+
| **`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> | |
|
|
241
|
+
| **`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> | |
|
|
242
|
+
| **`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 |
|
|
243
|
+
| **`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 |
|
|
244
|
+
| **`directUpdate`** | <code>boolean \| 'always' \| 'atInstall'</code> | Configure when the plugin should direct install updates. Only for autoUpdate mode. Works well for apps less than 10MB and with uploads done using --partial flag. Zip or apps more than 10MB will be relatively slow for users to update. - 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 |
|
|
245
|
+
| **`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. Requires autoUpdate and directUpdate to be enabled. Only available for Android and iOS. | <code>false</code> | 7.6.0 |
|
|
246
|
+
| **`autoSplashscreenLoader`** | <code>boolean</code> | Display a native loading indicator on top of the splashscreen while automatic direct updates are running. Only takes effect when {@link autoSplashscreen} is enabled. Requires the @capacitor/splash-screen plugin to be installed and configured with launchAutoHide: false. Only available for Android and iOS. | <code>false</code> | 7.19.0 |
|
|
247
|
+
| **`autoSplashscreenTimeout`** | <code>number</code> | Automatically hide the splashscreen after the specified number of milliseconds when using automatic direct updates. If the timeout elapses, the update continues to download in the background while the splashscreen is dismissed. Set to `0` (zero) to disable the timeout. When the timeout fires, the direct update flow is skipped and the downloaded bundle is installed on the next background/launch. Requires {@link autoSplashscreen} to be enabled. Only available for Android and iOS. | <code>10000 // (10 seconds)</code> | 7.19.0 |
|
|
248
|
+
| **`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>0 (disabled)</code> | |
|
|
249
|
+
| **`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 |
|
|
250
|
+
| **`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 |
|
|
251
|
+
| **`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 |
|
|
252
|
+
| **`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 |
|
|
253
|
+
| **`localSupaAnon`** | <code>string</code> | Configure the CLI to use a local server for testing. | <code>undefined</code> | 4.17.48 |
|
|
254
|
+
| **`localApi`** | <code>string</code> | Configure the CLI to use a local api for testing. | <code>undefined</code> | 6.3.3 |
|
|
255
|
+
| **`localApiFiles`** | <code>string</code> | Configure the CLI to use a local file api for testing. | <code>undefined</code> | 6.3.3 |
|
|
256
|
+
| **`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 |
|
|
257
|
+
| **`allowModifyAppId`** | <code>boolean</code> | Allow the plugin to modify the appId dynamically from the JavaScript side. | <code>false</code> | 7.14.0 |
|
|
258
|
+
| **`persistCustomId`** | <code>boolean</code> | Persist the customId set through {@link CapacitorUpdaterPlugin.setCustomId} across app restarts. Only available for Android and iOS. | <code>false (will be true by default in a future major release v8.x.x)</code> | 7.17.3 |
|
|
259
|
+
| **`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. This requires the channel to allow devices to self dissociate/associate in the channel settings. https://capgo.app/docs/public-api/channels/#channel-configuration-options | <code>undefined</code> | 5.5.0 |
|
|
260
|
+
| **`appId`** | <code>string</code> | Configure the app id for the app in the config. | <code>undefined</code> | 6.0.0 |
|
|
261
|
+
| **`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 |
|
|
262
|
+
| **`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 |
|
|
263
|
+
| **`shakeMenu`** | <code>boolean</code> | Enable shake gesture to show update menu for debugging/testing purposes | <code>false</code> | 7.5.0 |
|
|
262
264
|
|
|
263
265
|
### Examples
|
|
264
266
|
|
|
@@ -281,6 +283,8 @@ In `capacitor.config.json`:
|
|
|
281
283
|
"version": undefined,
|
|
282
284
|
"directUpdate": undefined,
|
|
283
285
|
"autoSplashscreen": undefined,
|
|
286
|
+
"autoSplashscreenLoader": undefined,
|
|
287
|
+
"autoSplashscreenTimeout": undefined,
|
|
284
288
|
"periodCheckDelay": 3600 (1 hour),
|
|
285
289
|
"localS3": undefined,
|
|
286
290
|
"localHost": undefined,
|
|
@@ -325,6 +329,8 @@ const config: CapacitorConfig = {
|
|
|
325
329
|
version: undefined,
|
|
326
330
|
directUpdate: undefined,
|
|
327
331
|
autoSplashscreen: undefined,
|
|
332
|
+
autoSplashscreenLoader: undefined,
|
|
333
|
+
autoSplashscreenTimeout: undefined,
|
|
328
334
|
periodCheckDelay: 3600 (1 hour),
|
|
329
335
|
localS3: undefined,
|
|
330
336
|
localHost: undefined,
|
|
@@ -12,8 +12,15 @@ import android.content.Context;
|
|
|
12
12
|
import android.content.SharedPreferences;
|
|
13
13
|
import android.content.pm.PackageInfo;
|
|
14
14
|
import android.content.pm.PackageManager;
|
|
15
|
+
import android.graphics.Color;
|
|
15
16
|
import android.os.Build;
|
|
17
|
+
import android.os.Handler;
|
|
16
18
|
import android.os.Looper;
|
|
19
|
+
import android.view.Gravity;
|
|
20
|
+
import android.view.View;
|
|
21
|
+
import android.view.ViewGroup;
|
|
22
|
+
import android.widget.FrameLayout;
|
|
23
|
+
import android.widget.ProgressBar;
|
|
17
24
|
import com.getcapacitor.CapConfig;
|
|
18
25
|
import com.getcapacitor.JSArray;
|
|
19
26
|
import com.getcapacitor.JSObject;
|
|
@@ -58,7 +65,7 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
58
65
|
private static final String channelUrlDefault = "https://plugin.capgo.app/channel_self";
|
|
59
66
|
private static final String CUSTOM_ID_PREF_KEY = "CapacitorUpdater.customId";
|
|
60
67
|
|
|
61
|
-
private final String PLUGIN_VERSION = "7.
|
|
68
|
+
private final String PLUGIN_VERSION = "7.19.2";
|
|
62
69
|
private static final String DELAY_CONDITION_PREFERENCES = "";
|
|
63
70
|
|
|
64
71
|
private SharedPreferences.Editor editor;
|
|
@@ -79,6 +86,9 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
79
86
|
private Boolean taskRunning = false;
|
|
80
87
|
private Boolean keepUrlPathAfterReload = false;
|
|
81
88
|
private Boolean autoSplashscreen = false;
|
|
89
|
+
private Boolean autoSplashscreenLoader = false;
|
|
90
|
+
private Integer autoSplashscreenTimeout = 10000;
|
|
91
|
+
private Boolean autoSplashscreenTimedOut = false;
|
|
82
92
|
private String directUpdateMode = "false";
|
|
83
93
|
private Boolean wasRecentlyInstalledOrUpdated = false;
|
|
84
94
|
Boolean shakeMenuEnabled = false;
|
|
@@ -96,6 +106,9 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
96
106
|
private DelayUpdateUtils delayUpdateUtils;
|
|
97
107
|
|
|
98
108
|
private ShakeMenu shakeMenu;
|
|
109
|
+
private final Handler mainHandler = new Handler(Looper.getMainLooper());
|
|
110
|
+
private FrameLayout splashscreenLoaderOverlay;
|
|
111
|
+
private Runnable splashscreenTimeoutRunnable;
|
|
99
112
|
|
|
100
113
|
private JSObject mapToJSObject(Map<String, Object> map) {
|
|
101
114
|
JSObject jsObject = new JSObject();
|
|
@@ -172,13 +185,7 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
172
185
|
}
|
|
173
186
|
this.currentVersionNative = new Version(this.getConfig().getString("version", pInfo.versionName));
|
|
174
187
|
this.currentBuildVersion = Integer.toString(pInfo.versionCode);
|
|
175
|
-
this.delayUpdateUtils = new DelayUpdateUtils(
|
|
176
|
-
this.prefs,
|
|
177
|
-
this.editor,
|
|
178
|
-
this.currentVersionNative,
|
|
179
|
-
CapacitorUpdaterPlugin.this::installNext,
|
|
180
|
-
logger
|
|
181
|
-
);
|
|
188
|
+
this.delayUpdateUtils = new DelayUpdateUtils(this.prefs, this.editor, this.currentVersionNative, logger);
|
|
182
189
|
} catch (final PackageManager.NameNotFoundException e) {
|
|
183
190
|
logger.error("Error instantiating implementation " + e.getMessage());
|
|
184
191
|
return;
|
|
@@ -252,6 +259,9 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
252
259
|
this.appReadyTimeout = this.getConfig().getInt("appReadyTimeout", 10000);
|
|
253
260
|
this.keepUrlPathAfterReload = this.getConfig().getBoolean("keepUrlPathAfterReload", false);
|
|
254
261
|
this.autoSplashscreen = this.getConfig().getBoolean("autoSplashscreen", false);
|
|
262
|
+
this.autoSplashscreenLoader = this.getConfig().getBoolean("autoSplashscreenLoader", false);
|
|
263
|
+
int splashscreenTimeoutValue = this.getConfig().getInt("autoSplashscreenTimeout", 10000);
|
|
264
|
+
this.autoSplashscreenTimeout = Math.max(0, splashscreenTimeoutValue);
|
|
255
265
|
this.implementation.timeout = this.getConfig().getInt("responseTimeout", 20) * 1000;
|
|
256
266
|
this.shakeMenuEnabled = this.getConfig().getBoolean("shakeMenu", false);
|
|
257
267
|
boolean resetWhenUpdate = this.getConfig().getBoolean("resetWhenUpdate", true);
|
|
@@ -311,7 +321,23 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
311
321
|
}
|
|
312
322
|
|
|
313
323
|
private void hideSplashscreen() {
|
|
324
|
+
if (Looper.myLooper() == Looper.getMainLooper()) {
|
|
325
|
+
hideSplashscreenInternal();
|
|
326
|
+
} else {
|
|
327
|
+
this.mainHandler.post(this::hideSplashscreenInternal);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
private void hideSplashscreenInternal() {
|
|
332
|
+
cancelSplashscreenTimeout();
|
|
333
|
+
removeSplashscreenLoader();
|
|
334
|
+
|
|
314
335
|
try {
|
|
336
|
+
if (getBridge() == null) {
|
|
337
|
+
logger.warn("Bridge not ready for hiding splashscreen with autoSplashscreen");
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
|
|
315
341
|
// Try to call the SplashScreen plugin directly through the bridge
|
|
316
342
|
PluginHandle splashScreenPlugin = getBridge().getPlugin("SplashScreen");
|
|
317
343
|
if (splashScreenPlugin != null) {
|
|
@@ -349,53 +375,135 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
349
375
|
}
|
|
350
376
|
|
|
351
377
|
private void showSplashscreen() {
|
|
378
|
+
if (Looper.myLooper() == Looper.getMainLooper()) {
|
|
379
|
+
showSplashscreenNow();
|
|
380
|
+
} else {
|
|
381
|
+
this.mainHandler.post(this::showSplashscreenNow);
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
private void showSplashscreenNow() {
|
|
386
|
+
cancelSplashscreenTimeout();
|
|
387
|
+
this.autoSplashscreenTimedOut = false;
|
|
388
|
+
|
|
352
389
|
try {
|
|
353
|
-
// Show splashscreen immediately and synchronously when backgrounding
|
|
354
390
|
if (getBridge() == null) {
|
|
355
391
|
logger.warn("Bridge not ready for showing splashscreen with autoSplashscreen");
|
|
356
|
-
return;
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
// Execute immediately on current thread if it's main, otherwise post to main thread
|
|
360
|
-
if (android.os.Looper.myLooper() == android.os.Looper.getMainLooper()) {
|
|
361
|
-
showSplashscreenNow();
|
|
362
392
|
} else {
|
|
363
|
-
|
|
364
|
-
if (
|
|
365
|
-
|
|
393
|
+
PluginHandle splashScreenPlugin = getBridge().getPlugin("SplashScreen");
|
|
394
|
+
if (splashScreenPlugin != null) {
|
|
395
|
+
JSObject options = new JSObject();
|
|
396
|
+
java.lang.reflect.Field msgHandlerField = getBridge().getClass().getDeclaredField("msgHandler");
|
|
397
|
+
msgHandlerField.setAccessible(true);
|
|
398
|
+
Object msgHandler = msgHandlerField.get(getBridge());
|
|
399
|
+
|
|
400
|
+
PluginCall call = new PluginCall(
|
|
401
|
+
(com.getcapacitor.MessageHandler) msgHandler,
|
|
402
|
+
"SplashScreen",
|
|
403
|
+
"FAKE_CALLBACK_ID_SHOW",
|
|
404
|
+
"show",
|
|
405
|
+
options
|
|
406
|
+
);
|
|
407
|
+
|
|
408
|
+
splashScreenPlugin.invoke("show", call);
|
|
409
|
+
logger.info("Splashscreen shown synchronously to prevent flash");
|
|
366
410
|
} else {
|
|
367
|
-
|
|
411
|
+
logger.warn("autoSplashscreen: SplashScreen plugin not found");
|
|
368
412
|
}
|
|
369
413
|
}
|
|
370
414
|
} catch (Exception e) {
|
|
371
|
-
logger.error("
|
|
415
|
+
logger.error("Failed to show splashscreen synchronously: " + e.getMessage());
|
|
372
416
|
}
|
|
417
|
+
|
|
418
|
+
addSplashscreenLoaderIfNeeded();
|
|
419
|
+
scheduleSplashscreenTimeout();
|
|
373
420
|
}
|
|
374
421
|
|
|
375
|
-
private void
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
JSObject options = new JSObject();
|
|
380
|
-
java.lang.reflect.Field msgHandlerField = getBridge().getClass().getDeclaredField("msgHandler");
|
|
381
|
-
msgHandlerField.setAccessible(true);
|
|
382
|
-
Object msgHandler = msgHandlerField.get(getBridge());
|
|
383
|
-
|
|
384
|
-
PluginCall call = new PluginCall(
|
|
385
|
-
(com.getcapacitor.MessageHandler) msgHandler,
|
|
386
|
-
"SplashScreen",
|
|
387
|
-
"FAKE_CALLBACK_ID_SHOW",
|
|
388
|
-
"show",
|
|
389
|
-
options
|
|
390
|
-
);
|
|
422
|
+
private void addSplashscreenLoaderIfNeeded() {
|
|
423
|
+
if (!Boolean.TRUE.equals(this.autoSplashscreenLoader)) {
|
|
424
|
+
return;
|
|
425
|
+
}
|
|
391
426
|
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
logger.warn("autoSplashscreen: SplashScreen plugin not found");
|
|
427
|
+
Runnable addLoader = () -> {
|
|
428
|
+
if (this.splashscreenLoaderOverlay != null) {
|
|
429
|
+
return;
|
|
396
430
|
}
|
|
397
|
-
|
|
398
|
-
|
|
431
|
+
|
|
432
|
+
Activity activity = getActivity();
|
|
433
|
+
if (activity == null) {
|
|
434
|
+
logger.warn("autoSplashscreen: Activity not available for loader overlay");
|
|
435
|
+
return;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
ProgressBar progressBar = new ProgressBar(activity);
|
|
439
|
+
progressBar.setIndeterminate(true);
|
|
440
|
+
|
|
441
|
+
FrameLayout overlay = new FrameLayout(activity);
|
|
442
|
+
overlay.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
|
|
443
|
+
overlay.setClickable(false);
|
|
444
|
+
overlay.setFocusable(false);
|
|
445
|
+
overlay.setBackgroundColor(Color.TRANSPARENT);
|
|
446
|
+
overlay.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
|
|
447
|
+
|
|
448
|
+
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
|
|
449
|
+
ViewGroup.LayoutParams.WRAP_CONTENT,
|
|
450
|
+
ViewGroup.LayoutParams.WRAP_CONTENT
|
|
451
|
+
);
|
|
452
|
+
params.gravity = Gravity.CENTER;
|
|
453
|
+
overlay.addView(progressBar, params);
|
|
454
|
+
|
|
455
|
+
ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView();
|
|
456
|
+
decorView.addView(overlay);
|
|
457
|
+
|
|
458
|
+
this.splashscreenLoaderOverlay = overlay;
|
|
459
|
+
};
|
|
460
|
+
|
|
461
|
+
if (Looper.myLooper() == Looper.getMainLooper()) {
|
|
462
|
+
addLoader.run();
|
|
463
|
+
} else {
|
|
464
|
+
this.mainHandler.post(addLoader);
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
private void removeSplashscreenLoader() {
|
|
469
|
+
Runnable removeLoader = () -> {
|
|
470
|
+
if (this.splashscreenLoaderOverlay != null) {
|
|
471
|
+
ViewGroup parent = (ViewGroup) this.splashscreenLoaderOverlay.getParent();
|
|
472
|
+
if (parent != null) {
|
|
473
|
+
parent.removeView(this.splashscreenLoaderOverlay);
|
|
474
|
+
}
|
|
475
|
+
this.splashscreenLoaderOverlay = null;
|
|
476
|
+
}
|
|
477
|
+
};
|
|
478
|
+
|
|
479
|
+
if (Looper.myLooper() == Looper.getMainLooper()) {
|
|
480
|
+
removeLoader.run();
|
|
481
|
+
} else {
|
|
482
|
+
this.mainHandler.post(removeLoader);
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
private void scheduleSplashscreenTimeout() {
|
|
487
|
+
if (this.autoSplashscreenTimeout == null || this.autoSplashscreenTimeout <= 0) {
|
|
488
|
+
return;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
cancelSplashscreenTimeout();
|
|
492
|
+
|
|
493
|
+
this.splashscreenTimeoutRunnable = () -> {
|
|
494
|
+
logger.info("autoSplashscreen timeout reached, hiding splashscreen");
|
|
495
|
+
this.autoSplashscreenTimedOut = true;
|
|
496
|
+
this.implementation.directUpdate = false;
|
|
497
|
+
hideSplashscreen();
|
|
498
|
+
};
|
|
499
|
+
|
|
500
|
+
this.mainHandler.postDelayed(this.splashscreenTimeoutRunnable, this.autoSplashscreenTimeout);
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
private void cancelSplashscreenTimeout() {
|
|
504
|
+
if (this.splashscreenTimeoutRunnable != null) {
|
|
505
|
+
this.mainHandler.removeCallbacks(this.splashscreenTimeoutRunnable);
|
|
506
|
+
this.splashscreenTimeoutRunnable = null;
|
|
399
507
|
}
|
|
400
508
|
}
|
|
401
509
|
|
|
@@ -415,6 +523,9 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
415
523
|
}
|
|
416
524
|
|
|
417
525
|
private boolean shouldUseDirectUpdate() {
|
|
526
|
+
if (Boolean.TRUE.equals(this.autoSplashscreenTimedOut)) {
|
|
527
|
+
return false;
|
|
528
|
+
}
|
|
418
529
|
switch (this.directUpdateMode) {
|
|
419
530
|
case "false":
|
|
420
531
|
return false;
|
|
@@ -432,6 +543,10 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
432
543
|
}
|
|
433
544
|
}
|
|
434
545
|
|
|
546
|
+
private boolean isDirectUpdateCurrentlyAllowed(final boolean plannedDirectUpdate) {
|
|
547
|
+
return plannedDirectUpdate && !Boolean.TRUE.equals(this.autoSplashscreenTimedOut);
|
|
548
|
+
}
|
|
549
|
+
|
|
435
550
|
private void directUpdateFinish(final BundleInfo latest) {
|
|
436
551
|
CapacitorUpdaterPlugin.this.implementation.set(latest);
|
|
437
552
|
CapacitorUpdaterPlugin.this._reload();
|
|
@@ -1259,9 +1374,12 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
1259
1374
|
}
|
|
1260
1375
|
|
|
1261
1376
|
private Thread backgroundDownload() {
|
|
1262
|
-
boolean
|
|
1263
|
-
|
|
1264
|
-
|
|
1377
|
+
final boolean plannedDirectUpdate = this.shouldUseDirectUpdate();
|
|
1378
|
+
final boolean initialDirectUpdateAllowed = this.isDirectUpdateCurrentlyAllowed(plannedDirectUpdate);
|
|
1379
|
+
this.implementation.directUpdate = initialDirectUpdateAllowed;
|
|
1380
|
+
final String messageUpdate = initialDirectUpdateAllowed
|
|
1381
|
+
? "Update will occur now."
|
|
1382
|
+
: "Update will occur next time app moves to background.";
|
|
1265
1383
|
return startNewThread(() -> {
|
|
1266
1384
|
logger.info("Check for update via: " + CapacitorUpdaterPlugin.this.updateUrl);
|
|
1267
1385
|
try {
|
|
@@ -1280,7 +1398,7 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
1280
1398
|
latestVersion,
|
|
1281
1399
|
current,
|
|
1282
1400
|
true,
|
|
1283
|
-
|
|
1401
|
+
plannedDirectUpdate
|
|
1284
1402
|
);
|
|
1285
1403
|
} else {
|
|
1286
1404
|
CapacitorUpdaterPlugin.this.endBackGroundTaskWithNotif(
|
|
@@ -1288,7 +1406,7 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
1288
1406
|
latestVersion,
|
|
1289
1407
|
current,
|
|
1290
1408
|
true,
|
|
1291
|
-
|
|
1409
|
+
plannedDirectUpdate,
|
|
1292
1410
|
"backend_refusal",
|
|
1293
1411
|
"backendRefused"
|
|
1294
1412
|
);
|
|
@@ -1310,7 +1428,7 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
1310
1428
|
latestVersion,
|
|
1311
1429
|
current,
|
|
1312
1430
|
true,
|
|
1313
|
-
|
|
1431
|
+
plannedDirectUpdate,
|
|
1314
1432
|
"backend_refusal",
|
|
1315
1433
|
"backendRefused"
|
|
1316
1434
|
);
|
|
@@ -1321,7 +1439,10 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
1321
1439
|
|
|
1322
1440
|
if ("builtin".equals(latestVersionName)) {
|
|
1323
1441
|
logger.info("Latest version is builtin");
|
|
1324
|
-
|
|
1442
|
+
final boolean directUpdateAllowedNow = CapacitorUpdaterPlugin.this.isDirectUpdateCurrentlyAllowed(
|
|
1443
|
+
plannedDirectUpdate
|
|
1444
|
+
);
|
|
1445
|
+
if (directUpdateAllowedNow) {
|
|
1325
1446
|
logger.info("Direct update to builtin version");
|
|
1326
1447
|
this._reset(false);
|
|
1327
1448
|
CapacitorUpdaterPlugin.this.endBackGroundTaskWithNotif(
|
|
@@ -1332,6 +1453,11 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
1332
1453
|
true
|
|
1333
1454
|
);
|
|
1334
1455
|
} else {
|
|
1456
|
+
if (plannedDirectUpdate && !directUpdateAllowedNow) {
|
|
1457
|
+
logger.info(
|
|
1458
|
+
"Direct update skipped because splashscreen timeout occurred. Update will be applied later."
|
|
1459
|
+
);
|
|
1460
|
+
}
|
|
1335
1461
|
logger.info("Setting next bundle to builtin");
|
|
1336
1462
|
CapacitorUpdaterPlugin.this.implementation.setNextBundle(BundleInfo.ID_BUILTIN);
|
|
1337
1463
|
CapacitorUpdaterPlugin.this.endBackGroundTaskWithNotif(
|
|
@@ -1351,7 +1477,7 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
1351
1477
|
current.getVersionName(),
|
|
1352
1478
|
current,
|
|
1353
1479
|
true,
|
|
1354
|
-
|
|
1480
|
+
plannedDirectUpdate
|
|
1355
1481
|
);
|
|
1356
1482
|
return;
|
|
1357
1483
|
}
|
|
@@ -1370,13 +1496,16 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
1370
1496
|
latestVersionName,
|
|
1371
1497
|
current,
|
|
1372
1498
|
true,
|
|
1373
|
-
|
|
1499
|
+
plannedDirectUpdate
|
|
1374
1500
|
);
|
|
1375
1501
|
return;
|
|
1376
1502
|
}
|
|
1377
1503
|
if (latest.isDownloaded()) {
|
|
1378
1504
|
logger.info("Latest bundle already exists and download is NOT required. " + messageUpdate);
|
|
1379
|
-
|
|
1505
|
+
final boolean directUpdateAllowedNow = CapacitorUpdaterPlugin.this.isDirectUpdateCurrentlyAllowed(
|
|
1506
|
+
plannedDirectUpdate
|
|
1507
|
+
);
|
|
1508
|
+
if (directUpdateAllowedNow) {
|
|
1380
1509
|
String delayUpdatePreferences = prefs.getString(DelayUpdateUtils.DELAY_CONDITION_PREFERENCES, "[]");
|
|
1381
1510
|
ArrayList<DelayCondition> delayConditionList = delayUpdateUtils.parseDelayConditions(
|
|
1382
1511
|
delayUpdatePreferences
|
|
@@ -1388,7 +1517,7 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
1388
1517
|
latestVersionName,
|
|
1389
1518
|
latest,
|
|
1390
1519
|
false,
|
|
1391
|
-
|
|
1520
|
+
plannedDirectUpdate
|
|
1392
1521
|
);
|
|
1393
1522
|
return;
|
|
1394
1523
|
}
|
|
@@ -1402,6 +1531,11 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
1402
1531
|
true
|
|
1403
1532
|
);
|
|
1404
1533
|
} else {
|
|
1534
|
+
if (plannedDirectUpdate && !directUpdateAllowedNow) {
|
|
1535
|
+
logger.info(
|
|
1536
|
+
"Direct update skipped because splashscreen timeout occurred. Update will install on next background."
|
|
1537
|
+
);
|
|
1538
|
+
}
|
|
1405
1539
|
CapacitorUpdaterPlugin.this.notifyListeners("updateAvailable", ret);
|
|
1406
1540
|
CapacitorUpdaterPlugin.this.implementation.setNextBundle(latest.getId());
|
|
1407
1541
|
CapacitorUpdaterPlugin.this.endBackGroundTaskWithNotif(
|
|
@@ -1467,7 +1601,7 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
1467
1601
|
latestVersionName,
|
|
1468
1602
|
CapacitorUpdaterPlugin.this.implementation.getCurrentBundle(),
|
|
1469
1603
|
true,
|
|
1470
|
-
|
|
1604
|
+
plannedDirectUpdate
|
|
1471
1605
|
);
|
|
1472
1606
|
}
|
|
1473
1607
|
});
|
|
@@ -1482,7 +1616,7 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
1482
1616
|
current.getVersionName(),
|
|
1483
1617
|
current,
|
|
1484
1618
|
true,
|
|
1485
|
-
|
|
1619
|
+
plannedDirectUpdate
|
|
1486
1620
|
);
|
|
1487
1621
|
}
|
|
1488
1622
|
});
|
|
@@ -1494,7 +1628,7 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
1494
1628
|
current.getVersionName(),
|
|
1495
1629
|
current,
|
|
1496
1630
|
true,
|
|
1497
|
-
|
|
1631
|
+
plannedDirectUpdate
|
|
1498
1632
|
);
|
|
1499
1633
|
}
|
|
1500
1634
|
});
|
|
@@ -19,19 +19,11 @@ public class DelayUpdateUtils {
|
|
|
19
19
|
private final SharedPreferences prefs;
|
|
20
20
|
private final SharedPreferences.Editor editor;
|
|
21
21
|
private final Version currentVersionNative;
|
|
22
|
-
private final Runnable installNext;
|
|
23
22
|
|
|
24
|
-
public DelayUpdateUtils(
|
|
25
|
-
SharedPreferences prefs,
|
|
26
|
-
SharedPreferences.Editor editor,
|
|
27
|
-
Version currentVersionNative,
|
|
28
|
-
Runnable installNext,
|
|
29
|
-
Logger logger
|
|
30
|
-
) {
|
|
23
|
+
public DelayUpdateUtils(SharedPreferences prefs, SharedPreferences.Editor editor, Version currentVersionNative, Logger logger) {
|
|
31
24
|
this.prefs = prefs;
|
|
32
25
|
this.editor = editor;
|
|
33
26
|
this.currentVersionNative = currentVersionNative;
|
|
34
|
-
this.installNext = installNext;
|
|
35
27
|
this.logger = logger;
|
|
36
28
|
}
|
|
37
29
|
|
|
@@ -96,7 +88,7 @@ public class DelayUpdateUtils {
|
|
|
96
88
|
break;
|
|
97
89
|
case DelayUntilNext.kill:
|
|
98
90
|
if (source == CancelDelaySource.KILLED) {
|
|
99
|
-
|
|
91
|
+
logger.info("Kill delay (value: " + value + ") condition removed at index " + index + " after app kill");
|
|
100
92
|
} else {
|
|
101
93
|
delayConditionListToKeep.add(condition);
|
|
102
94
|
logger.info(
|
|
@@ -160,7 +152,9 @@ public class DelayUpdateUtils {
|
|
|
160
152
|
index++;
|
|
161
153
|
}
|
|
162
154
|
|
|
163
|
-
if (
|
|
155
|
+
if (delayConditionListToKeep.isEmpty()) {
|
|
156
|
+
this.cancelDelay("checkCancelDelay");
|
|
157
|
+
} else {
|
|
164
158
|
this.setMultiDelay(convertDelayConditionsToJson(delayConditionListToKeep));
|
|
165
159
|
}
|
|
166
160
|
}
|
package/dist/docs.json
CHANGED
|
@@ -2451,6 +2451,38 @@
|
|
|
2451
2451
|
"complexTypes": [],
|
|
2452
2452
|
"type": "boolean | undefined"
|
|
2453
2453
|
},
|
|
2454
|
+
{
|
|
2455
|
+
"name": "autoSplashscreenLoader",
|
|
2456
|
+
"tags": [
|
|
2457
|
+
{
|
|
2458
|
+
"text": "false",
|
|
2459
|
+
"name": "default"
|
|
2460
|
+
},
|
|
2461
|
+
{
|
|
2462
|
+
"text": "7.19.0",
|
|
2463
|
+
"name": "since"
|
|
2464
|
+
}
|
|
2465
|
+
],
|
|
2466
|
+
"docs": "Display a native loading indicator on top of the splashscreen while automatic direct updates are running.\nOnly takes effect when {@link autoSplashscreen} is enabled.\nRequires the @capacitor/splash-screen plugin to be installed and configured with launchAutoHide: false.\n\nOnly available for Android and iOS.",
|
|
2467
|
+
"complexTypes": [],
|
|
2468
|
+
"type": "boolean | undefined"
|
|
2469
|
+
},
|
|
2470
|
+
{
|
|
2471
|
+
"name": "autoSplashscreenTimeout",
|
|
2472
|
+
"tags": [
|
|
2473
|
+
{
|
|
2474
|
+
"text": "10000 // (10 seconds)",
|
|
2475
|
+
"name": "default"
|
|
2476
|
+
},
|
|
2477
|
+
{
|
|
2478
|
+
"text": "7.19.0",
|
|
2479
|
+
"name": "since"
|
|
2480
|
+
}
|
|
2481
|
+
],
|
|
2482
|
+
"docs": "Automatically hide the splashscreen after the specified number of milliseconds when using automatic direct updates.\nIf the timeout elapses, the update continues to download in the background while the splashscreen is dismissed.\nSet to `0` (zero) to disable the timeout.\nWhen the timeout fires, the direct update flow is skipped and the downloaded bundle is installed on the next background/launch.\nRequires {@link autoSplashscreen} to be enabled.\n\nOnly available for Android and iOS.",
|
|
2483
|
+
"complexTypes": [],
|
|
2484
|
+
"type": "number | undefined"
|
|
2485
|
+
},
|
|
2454
2486
|
{
|
|
2455
2487
|
"name": "periodCheckDelay",
|
|
2456
2488
|
"tags": [
|
|
@@ -133,6 +133,30 @@ declare module '@capacitor/cli' {
|
|
|
133
133
|
* @since 7.6.0
|
|
134
134
|
*/
|
|
135
135
|
autoSplashscreen?: boolean;
|
|
136
|
+
/**
|
|
137
|
+
* Display a native loading indicator on top of the splashscreen while automatic direct updates are running.
|
|
138
|
+
* Only takes effect when {@link autoSplashscreen} is enabled.
|
|
139
|
+
* Requires the @capacitor/splash-screen plugin to be installed and configured with launchAutoHide: false.
|
|
140
|
+
*
|
|
141
|
+
* Only available for Android and iOS.
|
|
142
|
+
*
|
|
143
|
+
* @default false
|
|
144
|
+
* @since 7.19.0
|
|
145
|
+
*/
|
|
146
|
+
autoSplashscreenLoader?: boolean;
|
|
147
|
+
/**
|
|
148
|
+
* Automatically hide the splashscreen after the specified number of milliseconds when using automatic direct updates.
|
|
149
|
+
* If the timeout elapses, the update continues to download in the background while the splashscreen is dismissed.
|
|
150
|
+
* Set to `0` (zero) to disable the timeout.
|
|
151
|
+
* When the timeout fires, the direct update flow is skipped and the downloaded bundle is installed on the next background/launch.
|
|
152
|
+
* Requires {@link autoSplashscreen} to be enabled.
|
|
153
|
+
*
|
|
154
|
+
* Only available for Android and iOS.
|
|
155
|
+
*
|
|
156
|
+
* @default 10000 // (10 seconds)
|
|
157
|
+
* @since 7.19.0
|
|
158
|
+
*/
|
|
159
|
+
autoSplashscreenTimeout?: number;
|
|
136
160
|
/**
|
|
137
161
|
* Configure the delay period for period update check. the unit is in seconds.
|
|
138
162
|
*
|
|
@@ -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 seconds 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 * Works well for apps less than 10MB and with uploads done using --partial flag.\n * Zip or apps more than 10MB will be relatively slow for users to update.\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 * Requires autoUpdate and directUpdate to be enabled.\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 0 (disabled)\n * @example 3600 (1 hour)\n * @example 86400 (24 hours)\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 * Allow the plugin to modify the appId dynamically from the JavaScript side.\n *\n *\n * @default false\n * @since 7.14.0\n */\n allowModifyAppId?: boolean;\n\n /**\n * Persist the customId set through {@link CapacitorUpdaterPlugin.setCustomId} across app restarts.\n *\n * Only available for Android and iOS.\n *\n * @default false (will be true by default in a future major release v8.x.x)\n * @since 7.17.3\n */\n persistCustomId?: 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 * This requires the channel to allow devices to self dissociate/associate in the channel settings. https://capgo.app/docs/public-api/channels/#channel-configuration-options\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 * When {@link PluginsConfig.CapacitorUpdater.persistCustomId} is true, the value will be stored natively and restored on the next app launch.\n * Pass an empty string to remove any previously stored customId.\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, this event is retain till consumed.\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 * Get the configured App ID\n *\n * @returns {Promise<GetAppIdRes>} The current App ID\n * @throws {Error}\n * @since 7.14.0\n */\n getAppId(): Promise<GetAppIdRes>;\n\n /**\n * Set the App ID for the app (requires allowModifyAppId to be true in config)\n *\n * @param options The new App ID to set\n * @returns {Promise<void>}\n * @throws {Error} If allowModifyAppId is false or if the operation fails\n * @since 7.14.0\n */\n setAppId(options: SetAppIdOptions): Promise<void>;\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 /**\n * Custom identifier to associate with the device. Use an empty string to clear any saved value.\n */\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\nexport interface GetAppIdRes {\n appId: string;\n}\n\nexport interface SetAppIdOptions {\n appId: string;\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 seconds 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 * Works well for apps less than 10MB and with uploads done using --partial flag.\n * Zip or apps more than 10MB will be relatively slow for users to update.\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 * Requires autoUpdate and directUpdate to be enabled.\n *\n * Only available for Android and iOS.\n *\n * @default false\n * @since 7.6.0\n */\n autoSplashscreen?: boolean;\n\n /**\n * Display a native loading indicator on top of the splashscreen while automatic direct updates are running.\n * Only takes effect when {@link autoSplashscreen} is enabled.\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.19.0\n */\n autoSplashscreenLoader?: boolean;\n\n /**\n * Automatically hide the splashscreen after the specified number of milliseconds when using automatic direct updates.\n * If the timeout elapses, the update continues to download in the background while the splashscreen is dismissed.\n * Set to `0` (zero) to disable the timeout.\n * When the timeout fires, the direct update flow is skipped and the downloaded bundle is installed on the next background/launch.\n * Requires {@link autoSplashscreen} to be enabled.\n *\n * Only available for Android and iOS.\n *\n * @default 10000 // (10 seconds)\n * @since 7.19.0\n */\n autoSplashscreenTimeout?: number;\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 0 (disabled)\n * @example 3600 (1 hour)\n * @example 86400 (24 hours)\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 * Allow the plugin to modify the appId dynamically from the JavaScript side.\n *\n *\n * @default false\n * @since 7.14.0\n */\n allowModifyAppId?: boolean;\n\n /**\n * Persist the customId set through {@link CapacitorUpdaterPlugin.setCustomId} across app restarts.\n *\n * Only available for Android and iOS.\n *\n * @default false (will be true by default in a future major release v8.x.x)\n * @since 7.17.3\n */\n persistCustomId?: 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 * This requires the channel to allow devices to self dissociate/associate in the channel settings. https://capgo.app/docs/public-api/channels/#channel-configuration-options\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 * When {@link PluginsConfig.CapacitorUpdater.persistCustomId} is true, the value will be stored natively and restored on the next app launch.\n * Pass an empty string to remove any previously stored customId.\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, this event is retain till consumed.\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 * Get the configured App ID\n *\n * @returns {Promise<GetAppIdRes>} The current App ID\n * @throws {Error}\n * @since 7.14.0\n */\n getAppId(): Promise<GetAppIdRes>;\n\n /**\n * Set the App ID for the app (requires allowModifyAppId to be true in config)\n *\n * @param options The new App ID to set\n * @returns {Promise<void>}\n * @throws {Error} If allowModifyAppId is false or if the operation fails\n * @since 7.14.0\n */\n setAppId(options: SetAppIdOptions): Promise<void>;\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 /**\n * Custom identifier to associate with the device. Use an empty string to clear any saved value.\n */\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\nexport interface GetAppIdRes {\n appId: string;\n}\n\nexport interface SetAppIdOptions {\n appId: string;\n}\n"]}
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
import Foundation
|
|
8
8
|
import Capacitor
|
|
9
|
+
import UIKit
|
|
9
10
|
import Version
|
|
10
11
|
|
|
11
12
|
/**
|
|
@@ -50,7 +51,7 @@ public class CapacitorUpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
50
51
|
CAPPluginMethod(name: "isShakeMenuEnabled", returnType: CAPPluginReturnPromise)
|
|
51
52
|
]
|
|
52
53
|
public var implementation = CapgoUpdater()
|
|
53
|
-
private let PLUGIN_VERSION: String = "7.
|
|
54
|
+
private let PLUGIN_VERSION: String = "7.19.2"
|
|
54
55
|
static let updateUrlDefault = "https://plugin.capgo.app/updates"
|
|
55
56
|
static let statsUrlDefault = "https://plugin.capgo.app/stats"
|
|
56
57
|
static let channelUrlDefault = "https://plugin.capgo.app/channel_self"
|
|
@@ -69,6 +70,12 @@ public class CapacitorUpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
69
70
|
private var directUpdateMode: String = "false"
|
|
70
71
|
private var wasRecentlyInstalledOrUpdated = false
|
|
71
72
|
private var autoSplashscreen = false
|
|
73
|
+
private var autoSplashscreenLoader = false
|
|
74
|
+
private var autoSplashscreenTimeout = 10000
|
|
75
|
+
private var autoSplashscreenTimeoutWorkItem: DispatchWorkItem?
|
|
76
|
+
private var splashscreenLoaderView: UIActivityIndicatorView?
|
|
77
|
+
private var splashscreenLoaderContainer: UIView?
|
|
78
|
+
private var autoSplashscreenTimedOut = false
|
|
72
79
|
private var autoDeleteFailed = false
|
|
73
80
|
private var autoDeletePrevious = false
|
|
74
81
|
private var keepUrlPathAfterReload = false
|
|
@@ -141,6 +148,9 @@ public class CapacitorUpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
141
148
|
}
|
|
142
149
|
|
|
143
150
|
autoSplashscreen = getConfig().getBoolean("autoSplashscreen", false)
|
|
151
|
+
autoSplashscreenLoader = getConfig().getBoolean("autoSplashscreenLoader", false)
|
|
152
|
+
let splashscreenTimeoutValue = getConfig().getInt("autoSplashscreenTimeout", 10000)
|
|
153
|
+
autoSplashscreenTimeout = max(0, splashscreenTimeoutValue)
|
|
144
154
|
updateUrl = getConfig().getString("updateUrl", CapacitorUpdaterPlugin.updateUrlDefault)!
|
|
145
155
|
autoUpdate = getConfig().getBoolean("autoUpdate", true)
|
|
146
156
|
appReadyTimeout = getConfig().getInt("appReadyTimeout", 10000)
|
|
@@ -163,9 +173,7 @@ public class CapacitorUpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
163
173
|
CryptoCipher.setLogger(logger)
|
|
164
174
|
|
|
165
175
|
// Initialize DelayUpdateUtils
|
|
166
|
-
self.delayUpdateUtils = DelayUpdateUtils(currentVersionNative: currentVersionNative,
|
|
167
|
-
self?.installNext()
|
|
168
|
-
}, logger: logger)
|
|
176
|
+
self.delayUpdateUtils = DelayUpdateUtils(currentVersionNative: currentVersionNative, logger: logger)
|
|
169
177
|
let config = (self.bridge?.viewController as? CAPBridgeViewController)?.instanceDescriptor().legacyConfig
|
|
170
178
|
implementation.appId = Bundle.main.infoDictionary?["CFBundleIdentifier"] as? String ?? ""
|
|
171
179
|
implementation.appId = config?["appId"] as? String ?? implementation.appId
|
|
@@ -308,6 +316,7 @@ public class CapacitorUpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
308
316
|
return
|
|
309
317
|
}
|
|
310
318
|
self.statsUrl = url
|
|
319
|
+
self.implementation.statsUrl = url
|
|
311
320
|
call.resolve()
|
|
312
321
|
}
|
|
313
322
|
|
|
@@ -808,61 +817,204 @@ public class CapacitorUpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
808
817
|
}
|
|
809
818
|
|
|
810
819
|
private func hideSplashscreen() {
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
820
|
+
if Thread.isMainThread {
|
|
821
|
+
self.performHideSplashscreen()
|
|
822
|
+
} else {
|
|
823
|
+
DispatchQueue.main.async {
|
|
824
|
+
self.performHideSplashscreen()
|
|
815
825
|
}
|
|
826
|
+
}
|
|
827
|
+
}
|
|
816
828
|
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
}, error: { (_) in
|
|
821
|
-
self.logger.error("Failed to auto-hide splashscreen")
|
|
822
|
-
})
|
|
829
|
+
private func performHideSplashscreen() {
|
|
830
|
+
self.cancelSplashscreenTimeout()
|
|
831
|
+
self.removeSplashscreenLoader()
|
|
823
832
|
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
833
|
+
guard let bridge = self.bridge else {
|
|
834
|
+
self.logger.warn("Bridge not available for hiding splashscreen with autoSplashscreen")
|
|
835
|
+
return
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
// Create a plugin call for the hide method
|
|
839
|
+
let call = CAPPluginCall(callbackId: "autoHideSplashscreen", options: [:], success: { (_, _) in
|
|
840
|
+
self.logger.info("Splashscreen hidden automatically")
|
|
841
|
+
}, error: { (_) in
|
|
842
|
+
self.logger.error("Failed to auto-hide splashscreen")
|
|
843
|
+
})
|
|
844
|
+
|
|
845
|
+
// Try to call the SplashScreen hide method directly through the bridge
|
|
846
|
+
if let splashScreenPlugin = bridge.plugin(withName: "SplashScreen") {
|
|
847
|
+
// Use runtime method invocation to call hide method
|
|
848
|
+
let selector = NSSelectorFromString("hide:")
|
|
849
|
+
if splashScreenPlugin.responds(to: selector) {
|
|
850
|
+
_ = splashScreenPlugin.perform(selector, with: call)
|
|
851
|
+
self.logger.info("Called SplashScreen hide method")
|
|
834
852
|
} else {
|
|
835
|
-
self.logger.warn("autoSplashscreen: SplashScreen plugin not
|
|
853
|
+
self.logger.warn("autoSplashscreen: SplashScreen plugin does not respond to hide: method. Make sure @capacitor/splash-screen plugin is properly installed.")
|
|
836
854
|
}
|
|
855
|
+
} else {
|
|
856
|
+
self.logger.warn("autoSplashscreen: SplashScreen plugin not found. Install @capacitor/splash-screen plugin.")
|
|
837
857
|
}
|
|
838
858
|
}
|
|
839
859
|
|
|
840
860
|
private func showSplashscreen() {
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
861
|
+
if Thread.isMainThread {
|
|
862
|
+
self.performShowSplashscreen()
|
|
863
|
+
} else {
|
|
864
|
+
DispatchQueue.main.async {
|
|
865
|
+
self.performShowSplashscreen()
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
private func performShowSplashscreen() {
|
|
871
|
+
self.cancelSplashscreenTimeout()
|
|
872
|
+
self.autoSplashscreenTimedOut = false
|
|
873
|
+
|
|
874
|
+
guard let bridge = self.bridge else {
|
|
875
|
+
self.logger.warn("Bridge not available for showing splashscreen with autoSplashscreen")
|
|
876
|
+
return
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
// Create a plugin call for the show method
|
|
880
|
+
let call = CAPPluginCall(callbackId: "autoShowSplashscreen", options: [:], success: { (_, _) in
|
|
881
|
+
self.logger.info("Splashscreen shown automatically")
|
|
882
|
+
}, error: { (_) in
|
|
883
|
+
self.logger.error("Failed to auto-show splashscreen")
|
|
884
|
+
})
|
|
885
|
+
|
|
886
|
+
// Try to call the SplashScreen show method directly through the bridge
|
|
887
|
+
if let splashScreenPlugin = bridge.plugin(withName: "SplashScreen") {
|
|
888
|
+
// Use runtime method invocation to call show method
|
|
889
|
+
let selector = NSSelectorFromString("show:")
|
|
890
|
+
if splashScreenPlugin.responds(to: selector) {
|
|
891
|
+
_ = splashScreenPlugin.perform(selector, with: call)
|
|
892
|
+
self.logger.info("Called SplashScreen show method")
|
|
893
|
+
} else {
|
|
894
|
+
self.logger.warn("autoSplashscreen: SplashScreen plugin does not respond to show: method. Make sure @capacitor/splash-screen plugin is properly installed.")
|
|
895
|
+
}
|
|
896
|
+
} else {
|
|
897
|
+
self.logger.warn("autoSplashscreen: SplashScreen plugin not found. Install @capacitor/splash-screen plugin.")
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
self.addSplashscreenLoaderIfNeeded()
|
|
901
|
+
self.scheduleSplashscreenTimeout()
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
private func addSplashscreenLoaderIfNeeded() {
|
|
905
|
+
guard self.autoSplashscreenLoader else {
|
|
906
|
+
return
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
let addLoader = {
|
|
910
|
+
guard self.splashscreenLoaderContainer == nil else {
|
|
911
|
+
return
|
|
912
|
+
}
|
|
913
|
+
guard let rootView = self.bridge?.viewController?.view else {
|
|
914
|
+
self.logger.warn("autoSplashscreen: Unable to access root view for loader overlay")
|
|
844
915
|
return
|
|
845
916
|
}
|
|
846
917
|
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
self.logger.error("Failed to auto-show splashscreen")
|
|
852
|
-
})
|
|
918
|
+
let container = UIView()
|
|
919
|
+
container.translatesAutoresizingMaskIntoConstraints = false
|
|
920
|
+
container.backgroundColor = UIColor.clear
|
|
921
|
+
container.isUserInteractionEnabled = false
|
|
853
922
|
|
|
854
|
-
|
|
855
|
-
if
|
|
856
|
-
|
|
857
|
-
let selector = NSSelectorFromString("show:")
|
|
858
|
-
if splashScreenPlugin.responds(to: selector) {
|
|
859
|
-
_ = splashScreenPlugin.perform(selector, with: call)
|
|
860
|
-
self.logger.info("Called SplashScreen show method")
|
|
861
|
-
} else {
|
|
862
|
-
self.logger.warn("autoSplashscreen: SplashScreen plugin does not respond to show: method. Make sure @capacitor/splash-screen plugin is properly installed.")
|
|
863
|
-
}
|
|
923
|
+
let indicatorStyle: UIActivityIndicatorView.Style
|
|
924
|
+
if #available(iOS 13.0, *) {
|
|
925
|
+
indicatorStyle = .large
|
|
864
926
|
} else {
|
|
865
|
-
|
|
927
|
+
indicatorStyle = .whiteLarge
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
let indicator = UIActivityIndicatorView(style: indicatorStyle)
|
|
931
|
+
indicator.translatesAutoresizingMaskIntoConstraints = false
|
|
932
|
+
indicator.hidesWhenStopped = false
|
|
933
|
+
if #available(iOS 13.0, *) {
|
|
934
|
+
indicator.color = UIColor.label
|
|
935
|
+
}
|
|
936
|
+
indicator.startAnimating()
|
|
937
|
+
|
|
938
|
+
container.addSubview(indicator)
|
|
939
|
+
rootView.addSubview(container)
|
|
940
|
+
|
|
941
|
+
NSLayoutConstraint.activate([
|
|
942
|
+
container.leadingAnchor.constraint(equalTo: rootView.leadingAnchor),
|
|
943
|
+
container.trailingAnchor.constraint(equalTo: rootView.trailingAnchor),
|
|
944
|
+
container.topAnchor.constraint(equalTo: rootView.topAnchor),
|
|
945
|
+
container.bottomAnchor.constraint(equalTo: rootView.bottomAnchor),
|
|
946
|
+
indicator.centerXAnchor.constraint(equalTo: container.centerXAnchor),
|
|
947
|
+
indicator.centerYAnchor.constraint(equalTo: container.centerYAnchor)
|
|
948
|
+
])
|
|
949
|
+
|
|
950
|
+
self.splashscreenLoaderContainer = container
|
|
951
|
+
self.splashscreenLoaderView = indicator
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
if Thread.isMainThread {
|
|
955
|
+
addLoader()
|
|
956
|
+
} else {
|
|
957
|
+
DispatchQueue.main.async {
|
|
958
|
+
addLoader()
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
private func removeSplashscreenLoader() {
|
|
964
|
+
let removeLoader = {
|
|
965
|
+
self.splashscreenLoaderView?.stopAnimating()
|
|
966
|
+
self.splashscreenLoaderContainer?.removeFromSuperview()
|
|
967
|
+
self.splashscreenLoaderView = nil
|
|
968
|
+
self.splashscreenLoaderContainer = nil
|
|
969
|
+
}
|
|
970
|
+
|
|
971
|
+
if Thread.isMainThread {
|
|
972
|
+
removeLoader()
|
|
973
|
+
} else {
|
|
974
|
+
DispatchQueue.main.async {
|
|
975
|
+
removeLoader()
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
}
|
|
979
|
+
|
|
980
|
+
private func scheduleSplashscreenTimeout() {
|
|
981
|
+
guard self.autoSplashscreenTimeout > 0 else {
|
|
982
|
+
return
|
|
983
|
+
}
|
|
984
|
+
|
|
985
|
+
let scheduleTimeout = {
|
|
986
|
+
self.autoSplashscreenTimeoutWorkItem?.cancel()
|
|
987
|
+
|
|
988
|
+
let workItem = DispatchWorkItem { [weak self] in
|
|
989
|
+
guard let self = self else { return }
|
|
990
|
+
self.autoSplashscreenTimedOut = true
|
|
991
|
+
self.logger.info("autoSplashscreen timeout reached, hiding splashscreen")
|
|
992
|
+
self.hideSplashscreen()
|
|
993
|
+
}
|
|
994
|
+
self.autoSplashscreenTimeoutWorkItem = workItem
|
|
995
|
+
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(self.autoSplashscreenTimeout), execute: workItem)
|
|
996
|
+
}
|
|
997
|
+
|
|
998
|
+
if Thread.isMainThread {
|
|
999
|
+
scheduleTimeout()
|
|
1000
|
+
} else {
|
|
1001
|
+
DispatchQueue.main.async {
|
|
1002
|
+
scheduleTimeout()
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
private func cancelSplashscreenTimeout() {
|
|
1008
|
+
let cancelTimeout = {
|
|
1009
|
+
self.autoSplashscreenTimeoutWorkItem?.cancel()
|
|
1010
|
+
self.autoSplashscreenTimeoutWorkItem = nil
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
if Thread.isMainThread {
|
|
1014
|
+
cancelTimeout()
|
|
1015
|
+
} else {
|
|
1016
|
+
DispatchQueue.main.async {
|
|
1017
|
+
cancelTimeout()
|
|
866
1018
|
}
|
|
867
1019
|
}
|
|
868
1020
|
}
|
|
@@ -884,6 +1036,9 @@ public class CapacitorUpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
884
1036
|
}
|
|
885
1037
|
|
|
886
1038
|
private func shouldUseDirectUpdate() -> Bool {
|
|
1039
|
+
if self.autoSplashscreenTimedOut {
|
|
1040
|
+
return false
|
|
1041
|
+
}
|
|
887
1042
|
switch directUpdateMode {
|
|
888
1043
|
case "false":
|
|
889
1044
|
return false
|
|
@@ -920,8 +1075,8 @@ public class CapacitorUpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
920
1075
|
}
|
|
921
1076
|
|
|
922
1077
|
func backgroundDownload() {
|
|
923
|
-
let
|
|
924
|
-
let messageUpdate =
|
|
1078
|
+
let plannedDirectUpdate = self.shouldUseDirectUpdate()
|
|
1079
|
+
let messageUpdate = plannedDirectUpdate ? "Update will occur now." : "Update will occur next time app moves to background."
|
|
925
1080
|
guard let url = URL(string: self.updateUrl) else {
|
|
926
1081
|
logger.error("Error no url or wrong format")
|
|
927
1082
|
return
|
|
@@ -975,11 +1130,15 @@ public class CapacitorUpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
975
1130
|
}
|
|
976
1131
|
if res.version == "builtin" {
|
|
977
1132
|
self.logger.info("Latest version is builtin")
|
|
978
|
-
|
|
1133
|
+
let directUpdateAllowed = plannedDirectUpdate && !self.autoSplashscreenTimedOut
|
|
1134
|
+
if directUpdateAllowed {
|
|
979
1135
|
self.logger.info("Direct update to builtin version")
|
|
980
1136
|
_ = self._reset(toLastSuccessful: false)
|
|
981
1137
|
self.endBackGroundTaskWithNotif(msg: "Updated to builtin version", latestVersionName: res.version, current: self.implementation.getCurrentBundle(), error: false)
|
|
982
1138
|
} else {
|
|
1139
|
+
if plannedDirectUpdate && !directUpdateAllowed {
|
|
1140
|
+
self.logger.info("Direct update skipped because splashscreen timeout occurred. Update will apply later.")
|
|
1141
|
+
}
|
|
983
1142
|
self.logger.info("Setting next bundle to builtin")
|
|
984
1143
|
_ = self.implementation.setNextBundle(next: BundleInfo.ID_BUILTIN)
|
|
985
1144
|
self.endBackGroundTaskWithNotif(msg: "Next update will be to builtin version", latestVersionName: res.version, current: current, error: false)
|
|
@@ -1035,7 +1194,8 @@ public class CapacitorUpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
1035
1194
|
self.endBackGroundTaskWithNotif(msg: "Error checksum", latestVersionName: latestVersionName, current: current)
|
|
1036
1195
|
return
|
|
1037
1196
|
}
|
|
1038
|
-
|
|
1197
|
+
let directUpdateAllowed = plannedDirectUpdate && !self.autoSplashscreenTimedOut
|
|
1198
|
+
if directUpdateAllowed {
|
|
1039
1199
|
let delayUpdatePreferences = UserDefaults.standard.string(forKey: DelayUpdateUtils.DELAY_CONDITION_PREFERENCES) ?? "[]"
|
|
1040
1200
|
let delayConditionList: [DelayCondition] = self.fromJsonArr(json: delayUpdatePreferences).map { obj -> DelayCondition in
|
|
1041
1201
|
let kind: String = obj.value(forKey: "kind") as! String
|
|
@@ -1051,6 +1211,9 @@ public class CapacitorUpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
1051
1211
|
_ = self._reload()
|
|
1052
1212
|
self.endBackGroundTaskWithNotif(msg: "update installed", latestVersionName: latestVersionName, current: next, error: false)
|
|
1053
1213
|
} else {
|
|
1214
|
+
if plannedDirectUpdate && !directUpdateAllowed {
|
|
1215
|
+
self.logger.info("Direct update skipped because splashscreen timeout occurred. Update will install on next app background.")
|
|
1216
|
+
}
|
|
1054
1217
|
self.notifyListeners("updateAvailable", data: ["bundle": next.toJSON()])
|
|
1055
1218
|
_ = self.implementation.setNextBundle(next: next.getId())
|
|
1056
1219
|
self.endBackGroundTaskWithNotif(msg: "update downloaded, will install next background", latestVersionName: latestVersionName, current: current, error: false)
|
|
@@ -22,7 +22,6 @@ public class DelayUpdateUtils {
|
|
|
22
22
|
private let logger: Logger
|
|
23
23
|
|
|
24
24
|
private let currentVersionNative: Version
|
|
25
|
-
private let installNext: () -> Void
|
|
26
25
|
|
|
27
26
|
public enum CancelDelaySource {
|
|
28
27
|
case killed
|
|
@@ -38,9 +37,8 @@ public class DelayUpdateUtils {
|
|
|
38
37
|
}
|
|
39
38
|
}
|
|
40
39
|
|
|
41
|
-
public init(currentVersionNative: Version,
|
|
40
|
+
public init(currentVersionNative: Version, logger: Logger) {
|
|
42
41
|
self.currentVersionNative = currentVersionNative
|
|
43
|
-
self.installNext = installNext
|
|
44
42
|
self.logger = logger
|
|
45
43
|
}
|
|
46
44
|
|
|
@@ -84,7 +82,7 @@ public class DelayUpdateUtils {
|
|
|
84
82
|
|
|
85
83
|
case "kill":
|
|
86
84
|
if source == .killed {
|
|
87
|
-
|
|
85
|
+
logger.info("Kill delay (value: \(value ?? "")) condition removed at index \(index) after app kill")
|
|
88
86
|
} else {
|
|
89
87
|
delayConditionListToKeep.append(condition)
|
|
90
88
|
logger.info("Kill delay (value: \(value ?? "")) condition kept at index \(index) (source: \(source.description))")
|