@capgo/capacitor-updater 7.40.2 → 7.41.1
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 +135 -0
- package/android/src/main/java/ee/forgr/capacitor_updater/CapacitorUpdaterPlugin.java +1 -1
- package/android/src/main/java/ee/forgr/capacitor_updater/CapgoUpdater.java +4 -1
- package/android/src/main/java/ee/forgr/capacitor_updater/CryptoCipher.java +6 -4
- package/android/src/main/java/ee/forgr/capacitor_updater/DownloadService.java +12 -9
- package/dist/docs.json +557 -1
- package/dist/esm/definitions.d.ts +319 -0
- package/dist/esm/definitions.js.map +1 -1
- package/dist/esm/index.d.ts +0 -1
- package/dist/esm/index.js +0 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/plugin.cjs.js +0 -1
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +2 -2
- package/dist/plugin.js.map +1 -1
- package/ios/Sources/CapacitorUpdaterPlugin/AES.swift +26 -8
- package/ios/Sources/CapacitorUpdaterPlugin/BigInt.swift +9 -9
- package/ios/Sources/CapacitorUpdaterPlugin/BundleInfo.swift +51 -14
- package/ios/Sources/CapacitorUpdaterPlugin/BundleStatus.swift +11 -11
- package/ios/Sources/CapacitorUpdaterPlugin/CapacitorUpdaterPlugin.swift +1 -1
- package/ios/Sources/CapacitorUpdaterPlugin/CapgoUpdater.swift +304 -146
- package/ios/Sources/CapacitorUpdaterPlugin/CryptoCipher.swift +10 -6
- package/ios/Sources/CapacitorUpdaterPlugin/DelayUpdateUtils.swift +23 -7
- package/ios/Sources/CapacitorUpdaterPlugin/InternalUtils.swift +58 -1
- package/ios/Sources/CapacitorUpdaterPlugin/Logger.swift +9 -9
- package/ios/Sources/CapacitorUpdaterPlugin/ShakeMenu.swift +6 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -257,7 +257,142 @@ Capacitor Updater works by unzipping a compiled app bundle to the native device
|
|
|
257
257
|
<docgen-config>
|
|
258
258
|
<!--Update the source file JSDoc comments and rerun docgen to update the docs below-->
|
|
259
259
|
|
|
260
|
+
CapacitorUpdater can be configured with these options:
|
|
261
|
+
|
|
262
|
+
| Prop | Type | Description | Default | Since |
|
|
263
|
+
| ----------------------------- | ------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- | ------- |
|
|
264
|
+
| **`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> | |
|
|
265
|
+
| **`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> | |
|
|
266
|
+
| **`autoDeleteFailed`** | <code>boolean</code> | Configure whether the plugin should use automatically delete failed bundles. Only available for Android and iOS. | <code>true</code> | |
|
|
267
|
+
| **`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> | |
|
|
268
|
+
| **`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> | |
|
|
269
|
+
| **`resetWhenUpdate`** | <code>boolean</code> | Automatically delete previous downloaded bundles when a newer native app bundle is installed to the device. Setting this to false can broke the auto update flow if the user download from the store a native app bundle that is older than the current downloaded bundle. Upload will be prevented by channel setting downgrade_under_native. Only available for Android and iOS. | <code>true</code> | |
|
|
270
|
+
| **`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> | |
|
|
271
|
+
| **`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> | |
|
|
272
|
+
| **`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> | |
|
|
273
|
+
| **`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 |
|
|
274
|
+
| **`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 |
|
|
275
|
+
| **`directUpdate`** | <code>boolean \| 'always' \| 'atInstall' \| 'onLaunch'</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 (use default behavior: download at start, set when backgrounded) - atInstall: Direct update only when app is installed, updated from store, otherwise act as directUpdate = false - onLaunch: Direct update only on app installed, updated from store or after app kill, otherwise act as directUpdate = false - always: Direct update in all previous cases (app installed, updated from store, after app kill or app resume), never act as directUpdate = false - true: (deprecated) Same as "always" for backward compatibility Only available for Android and iOS. | <code>false</code> | 5.1.0 |
|
|
276
|
+
| **`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", "onLaunch", 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 |
|
|
277
|
+
| **`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 |
|
|
278
|
+
| **`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 |
|
|
279
|
+
| **`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> | |
|
|
280
|
+
| **`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 |
|
|
281
|
+
| **`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 |
|
|
282
|
+
| **`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 |
|
|
283
|
+
| **`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 |
|
|
284
|
+
| **`localSupaAnon`** | <code>string</code> | Configure the CLI to use a local server for testing. | <code>undefined</code> | 4.17.48 |
|
|
285
|
+
| **`localApi`** | <code>string</code> | Configure the CLI to use a local api for testing. | <code>undefined</code> | 6.3.3 |
|
|
286
|
+
| **`localApiFiles`** | <code>string</code> | Configure the CLI to use a local file api for testing. | <code>undefined</code> | 6.3.3 |
|
|
287
|
+
| **`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 |
|
|
288
|
+
| **`allowModifyAppId`** | <code>boolean</code> | Allow the plugin to modify the appId dynamically from the JavaScript side. | <code>false</code> | 7.14.0 |
|
|
289
|
+
| **`allowManualBundleError`** | <code>boolean</code> | Allow marking bundles as errored from JavaScript while using manual update flows. When enabled, {@link CapacitorUpdaterPlugin.setBundleError} can change a bundle status to `error`. | <code>false</code> | 7.20.0 |
|
|
290
|
+
| **`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 |
|
|
291
|
+
| **`persistModifyUrl`** | <code>boolean</code> | Persist the updateUrl, statsUrl and channelUrl set through {@link CapacitorUpdaterPlugin.setUpdateUrl}, {@link CapacitorUpdaterPlugin.setStatsUrl} and {@link CapacitorUpdaterPlugin.setChannelUrl} across app restarts. Only available for Android and iOS. | <code>false</code> | 7.20.0 |
|
|
292
|
+
| **`allowSetDefaultChannel`** | <code>boolean</code> | Allow or disallow the {@link CapacitorUpdaterPlugin.setChannel} method to modify the defaultChannel. When set to `false`, calling `setChannel()` will return an error with code `disabled_by_config`. | <code>true</code> | 7.34.0 |
|
|
293
|
+
| **`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 |
|
|
294
|
+
| **`appId`** | <code>string</code> | Configure the app id for the app in the config. | <code>undefined</code> | 6.0.0 |
|
|
295
|
+
| **`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 |
|
|
296
|
+
| **`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 |
|
|
297
|
+
| **`shakeMenu`** | <code>boolean</code> | Enable shake gesture to show update menu for debugging/testing purposes | <code>false</code> | 7.5.0 |
|
|
298
|
+
|
|
299
|
+
### Examples
|
|
300
|
+
|
|
301
|
+
In `capacitor.config.json`:
|
|
260
302
|
|
|
303
|
+
```json
|
|
304
|
+
{
|
|
305
|
+
"plugins": {
|
|
306
|
+
"CapacitorUpdater": {
|
|
307
|
+
"appReadyTimeout": 1000 // (1 second, minimum 1000),
|
|
308
|
+
"responseTimeout": 10 // (10 second),
|
|
309
|
+
"autoDeleteFailed": false,
|
|
310
|
+
"autoDeletePrevious": false,
|
|
311
|
+
"autoUpdate": false,
|
|
312
|
+
"resetWhenUpdate": false,
|
|
313
|
+
"updateUrl": https://example.com/api/auto_update,
|
|
314
|
+
"channelUrl": https://example.com/api/channel,
|
|
315
|
+
"statsUrl": https://example.com/api/stats,
|
|
316
|
+
"publicKey": undefined,
|
|
317
|
+
"version": undefined,
|
|
318
|
+
"directUpdate": undefined,
|
|
319
|
+
"autoSplashscreen": undefined,
|
|
320
|
+
"autoSplashscreenLoader": undefined,
|
|
321
|
+
"autoSplashscreenTimeout": undefined,
|
|
322
|
+
"periodCheckDelay": 3600 (1 hour),
|
|
323
|
+
"localS3": undefined,
|
|
324
|
+
"localHost": undefined,
|
|
325
|
+
"localWebHost": undefined,
|
|
326
|
+
"localSupa": undefined,
|
|
327
|
+
"localSupaAnon": undefined,
|
|
328
|
+
"localApi": undefined,
|
|
329
|
+
"localApiFiles": undefined,
|
|
330
|
+
"allowModifyUrl": undefined,
|
|
331
|
+
"allowModifyAppId": undefined,
|
|
332
|
+
"allowManualBundleError": undefined,
|
|
333
|
+
"persistCustomId": undefined,
|
|
334
|
+
"persistModifyUrl": undefined,
|
|
335
|
+
"allowSetDefaultChannel": undefined,
|
|
336
|
+
"defaultChannel": undefined,
|
|
337
|
+
"appId": undefined,
|
|
338
|
+
"keepUrlPathAfterReload": undefined,
|
|
339
|
+
"disableJSLogging": undefined,
|
|
340
|
+
"shakeMenu": undefined
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
In `capacitor.config.ts`:
|
|
347
|
+
|
|
348
|
+
```ts
|
|
349
|
+
/// <reference types="@capgo/capacitor-updater" />
|
|
350
|
+
|
|
351
|
+
import { CapacitorConfig } from '@capacitor/cli';
|
|
352
|
+
|
|
353
|
+
const config: CapacitorConfig = {
|
|
354
|
+
plugins: {
|
|
355
|
+
CapacitorUpdater: {
|
|
356
|
+
appReadyTimeout: 1000 // (1 second, minimum 1000),
|
|
357
|
+
responseTimeout: 10 // (10 second),
|
|
358
|
+
autoDeleteFailed: false,
|
|
359
|
+
autoDeletePrevious: false,
|
|
360
|
+
autoUpdate: false,
|
|
361
|
+
resetWhenUpdate: false,
|
|
362
|
+
updateUrl: https://example.com/api/auto_update,
|
|
363
|
+
channelUrl: https://example.com/api/channel,
|
|
364
|
+
statsUrl: https://example.com/api/stats,
|
|
365
|
+
publicKey: undefined,
|
|
366
|
+
version: undefined,
|
|
367
|
+
directUpdate: undefined,
|
|
368
|
+
autoSplashscreen: undefined,
|
|
369
|
+
autoSplashscreenLoader: undefined,
|
|
370
|
+
autoSplashscreenTimeout: undefined,
|
|
371
|
+
periodCheckDelay: 3600 (1 hour),
|
|
372
|
+
localS3: undefined,
|
|
373
|
+
localHost: undefined,
|
|
374
|
+
localWebHost: undefined,
|
|
375
|
+
localSupa: undefined,
|
|
376
|
+
localSupaAnon: undefined,
|
|
377
|
+
localApi: undefined,
|
|
378
|
+
localApiFiles: undefined,
|
|
379
|
+
allowModifyUrl: undefined,
|
|
380
|
+
allowModifyAppId: undefined,
|
|
381
|
+
allowManualBundleError: undefined,
|
|
382
|
+
persistCustomId: undefined,
|
|
383
|
+
persistModifyUrl: undefined,
|
|
384
|
+
allowSetDefaultChannel: undefined,
|
|
385
|
+
defaultChannel: undefined,
|
|
386
|
+
appId: undefined,
|
|
387
|
+
keepUrlPathAfterReload: undefined,
|
|
388
|
+
disableJSLogging: undefined,
|
|
389
|
+
shakeMenu: undefined,
|
|
390
|
+
},
|
|
391
|
+
},
|
|
392
|
+
};
|
|
393
|
+
|
|
394
|
+
export default config;
|
|
395
|
+
```
|
|
261
396
|
|
|
262
397
|
</docgen-config>
|
|
263
398
|
|
|
@@ -85,7 +85,7 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
85
85
|
private static final String[] BREAKING_EVENT_NAMES = { "breakingAvailable", "majorAvailable" };
|
|
86
86
|
private static final String LAST_FAILED_BUNDLE_PREF_KEY = "CapacitorUpdater.lastFailedBundle";
|
|
87
87
|
|
|
88
|
-
private final String pluginVersion = "7.
|
|
88
|
+
private final String pluginVersion = "7.41.1";
|
|
89
89
|
private static final String DELAY_CONDITION_PREFERENCES = "";
|
|
90
90
|
|
|
91
91
|
private SharedPreferences.Editor editor;
|
|
@@ -105,7 +105,10 @@ public class CapgoUpdater {
|
|
|
105
105
|
|
|
106
106
|
private boolean isProd() {
|
|
107
107
|
try {
|
|
108
|
-
|
|
108
|
+
if (activity == null) {
|
|
109
|
+
return true; // Default to production if no activity context
|
|
110
|
+
}
|
|
111
|
+
return (activity.getApplicationInfo().flags & android.content.pm.ApplicationInfo.FLAG_DEBUGGABLE) == 0;
|
|
109
112
|
} catch (Exception e) {
|
|
110
113
|
return true; // Default to production if we can't determine
|
|
111
114
|
}
|
|
@@ -357,8 +357,10 @@ public class CryptoCipher {
|
|
|
357
357
|
}
|
|
358
358
|
|
|
359
359
|
/**
|
|
360
|
-
* Get first
|
|
361
|
-
* Returns
|
|
360
|
+
* Get first 20 characters of the public key for identification.
|
|
361
|
+
* Returns 20-character string or empty string if key is invalid/empty.
|
|
362
|
+
* The first 12 chars are always "MIIBCgKCAQEA" for RSA 2048-bit keys,
|
|
363
|
+
* so the unique part starts at character 13.
|
|
362
364
|
*/
|
|
363
365
|
public static String calcKeyId(String publicKey) {
|
|
364
366
|
if (publicKey == null || publicKey.isEmpty()) {
|
|
@@ -371,7 +373,7 @@ public class CryptoCipher {
|
|
|
371
373
|
.replace("-----BEGINRSAPUBLICKEY-----", "")
|
|
372
374
|
.replace("-----ENDRSAPUBLICKEY-----", "");
|
|
373
375
|
|
|
374
|
-
// Return first
|
|
375
|
-
return cleanedKey.length() >=
|
|
376
|
+
// Return first 20 characters of the base64-encoded key
|
|
377
|
+
return cleanedKey.length() >= 20 ? cleanedKey.substring(0, 20) : cleanedKey;
|
|
376
378
|
}
|
|
377
379
|
}
|
|
@@ -388,8 +388,9 @@ public class DownloadService extends Worker {
|
|
|
388
388
|
sendStatsAsync("download_zip_start", version);
|
|
389
389
|
|
|
390
390
|
File target = new File(documentsDir, dest);
|
|
391
|
-
|
|
392
|
-
File
|
|
391
|
+
// Use bundle ID in temp file names to prevent collisions when multiple downloads run concurrently
|
|
392
|
+
File infoFile = new File(documentsDir, "update_" + id + ".dat");
|
|
393
|
+
File tempFile = new File(documentsDir, "temp_" + id + ".tmp");
|
|
393
394
|
|
|
394
395
|
// Check available disk space before starting
|
|
395
396
|
long availableSpace = target.getParentFile().getUsableSpace();
|
|
@@ -420,7 +421,7 @@ public class DownloadService extends Worker {
|
|
|
420
421
|
reader = new BufferedReader(new FileReader(infoFile));
|
|
421
422
|
String updateVersion = reader.readLine();
|
|
422
423
|
if (updateVersion != null && !updateVersion.equals(version)) {
|
|
423
|
-
clearDownloadData(documentsDir);
|
|
424
|
+
clearDownloadData(documentsDir, id);
|
|
424
425
|
} else {
|
|
425
426
|
downloadedBytes = tempFile.length();
|
|
426
427
|
}
|
|
@@ -432,7 +433,7 @@ public class DownloadService extends Worker {
|
|
|
432
433
|
}
|
|
433
434
|
}
|
|
434
435
|
} else {
|
|
435
|
-
clearDownloadData(documentsDir);
|
|
436
|
+
clearDownloadData(documentsDir, id);
|
|
436
437
|
}
|
|
437
438
|
|
|
438
439
|
if (downloadedBytes > 0) {
|
|
@@ -544,9 +545,9 @@ public class DownloadService extends Worker {
|
|
|
544
545
|
}
|
|
545
546
|
}
|
|
546
547
|
|
|
547
|
-
private void clearDownloadData(String docDir) {
|
|
548
|
-
File tempFile = new File(docDir, "
|
|
549
|
-
File infoFile = new File(docDir,
|
|
548
|
+
private void clearDownloadData(String docDir, String id) {
|
|
549
|
+
File tempFile = new File(docDir, "temp_" + id + ".tmp");
|
|
550
|
+
File infoFile = new File(docDir, "update_" + id + ".dat");
|
|
550
551
|
try {
|
|
551
552
|
tempFile.delete();
|
|
552
553
|
infoFile.delete();
|
|
@@ -824,12 +825,14 @@ public class DownloadService extends Worker {
|
|
|
824
825
|
}
|
|
825
826
|
|
|
826
827
|
/**
|
|
827
|
-
* Clean up old temporary files
|
|
828
|
+
* Clean up old temporary files (both .tmp and update_*.dat files)
|
|
828
829
|
*/
|
|
829
830
|
private void cleanupOldTempFiles(File directory) {
|
|
830
831
|
if (directory == null || !directory.exists()) return;
|
|
831
832
|
|
|
832
|
-
File[] tempFiles = directory.listFiles(
|
|
833
|
+
File[] tempFiles = directory.listFiles(
|
|
834
|
+
(dir, name) -> name.endsWith(".tmp") || (name.startsWith("update_") && name.endsWith(".dat"))
|
|
835
|
+
);
|
|
833
836
|
if (tempFiles != null) {
|
|
834
837
|
long oneHourAgo = System.currentTimeMillis() - 3600000;
|
|
835
838
|
for (File tempFile : tempFiles) {
|