@capgo/capacitor-updater 7.4.0 → 7.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +115 -28
- package/android/src/main/java/ee/forgr/capacitor_updater/CapacitorUpdaterPlugin.java +209 -11
- package/android/src/main/java/ee/forgr/capacitor_updater/CapgoUpdater.java +134 -0
- package/android/src/main/java/ee/forgr/capacitor_updater/ShakeDetector.java +72 -0
- package/android/src/main/java/ee/forgr/capacitor_updater/ShakeMenu.java +169 -0
- package/dist/docs.json +230 -2
- package/dist/esm/definitions.d.ts +91 -3
- package/dist/esm/definitions.js.map +1 -1
- package/dist/esm/web.d.ts +4 -1
- package/dist/esm/web.js +14 -2
- package/dist/esm/web.js.map +1 -1
- package/dist/plugin.cjs.js +14 -2
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +14 -2
- package/dist/plugin.js.map +1 -1
- package/ios/Plugin/CapacitorUpdaterPlugin.swift +153 -11
- package/ios/Plugin/CapgoUpdater.swift +96 -39
- package/ios/Plugin/InternalUtils.swift +45 -0
- package/ios/Plugin/ShakeMenu.swift +112 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -225,33 +225,35 @@ Capacitor Updater works by unzipping a compiled app bundle to the native device
|
|
|
225
225
|
|
|
226
226
|
CapacitorUpdater can be configured with these options:
|
|
227
227
|
|
|
228
|
-
| Prop | Type
|
|
229
|
-
| ---------------------------- |
|
|
230
|
-
| **`appReadyTimeout`** | <code>number</code>
|
|
231
|
-
| **`responseTimeout`** | <code>number</code>
|
|
232
|
-
| **`autoDeleteFailed`** | <code>boolean</code>
|
|
233
|
-
| **`autoDeletePrevious`** | <code>boolean</code>
|
|
234
|
-
| **`autoUpdate`** | <code>boolean</code>
|
|
235
|
-
| **`resetWhenUpdate`** | <code>boolean</code>
|
|
236
|
-
| **`updateUrl`** | <code>string</code>
|
|
237
|
-
| **`channelUrl`** | <code>string</code>
|
|
238
|
-
| **`statsUrl`** | <code>string</code>
|
|
239
|
-
| **`publicKey`** | <code>string</code>
|
|
240
|
-
| **`version`** | <code>string</code>
|
|
241
|
-
| **`directUpdate`** | <code>boolean</code> |
|
|
242
|
-
| **`
|
|
243
|
-
| **`
|
|
244
|
-
| **`
|
|
245
|
-
| **`
|
|
246
|
-
| **`
|
|
247
|
-
| **`
|
|
248
|
-
| **`
|
|
249
|
-
| **`
|
|
250
|
-
| **`
|
|
251
|
-
| **`
|
|
252
|
-
| **`
|
|
253
|
-
| **`
|
|
254
|
-
| **`
|
|
228
|
+
| Prop | Type | Description | Default | Since |
|
|
229
|
+
| ---------------------------- | ----------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------- | ------- |
|
|
230
|
+
| **`appReadyTimeout`** | <code>number</code> | Configure the number of milliseconds the native plugin should wait before considering an update 'failed'. Only available for Android and iOS. | <code>10000 // (10 seconds)</code> | |
|
|
231
|
+
| **`responseTimeout`** | <code>number</code> | Configure the number of milliseconds the native plugin should wait before considering API timeout. Only available for Android and iOS. | <code>20 // (20 second)</code> | |
|
|
232
|
+
| **`autoDeleteFailed`** | <code>boolean</code> | Configure whether the plugin should use automatically delete failed bundles. Only available for Android and iOS. | <code>true</code> | |
|
|
233
|
+
| **`autoDeletePrevious`** | <code>boolean</code> | Configure whether the plugin should use automatically delete previous bundles after a successful update. Only available for Android and iOS. | <code>true</code> | |
|
|
234
|
+
| **`autoUpdate`** | <code>boolean</code> | Configure whether the plugin should use Auto Update via an update server. Only available for Android and iOS. | <code>true</code> | |
|
|
235
|
+
| **`resetWhenUpdate`** | <code>boolean</code> | Automatically delete previous downloaded bundles when a newer native app bundle is installed to the device. Only available for Android and iOS. | <code>true</code> | |
|
|
236
|
+
| **`updateUrl`** | <code>string</code> | Configure the URL / endpoint to which update checks are sent. Only available for Android and iOS. | <code>https://plugin.capgo.app/updates</code> | |
|
|
237
|
+
| **`channelUrl`** | <code>string</code> | Configure the URL / endpoint for channel operations. Only available for Android and iOS. | <code>https://plugin.capgo.app/channel_self</code> | |
|
|
238
|
+
| **`statsUrl`** | <code>string</code> | Configure the URL / endpoint to which update statistics are sent. Only available for Android and iOS. Set to "" to disable stats reporting. | <code>https://plugin.capgo.app/stats</code> | |
|
|
239
|
+
| **`publicKey`** | <code>string</code> | Configure the public key for end to end live update encryption Version 2 Only available for Android and iOS. | <code>undefined</code> | 6.2.0 |
|
|
240
|
+
| **`version`** | <code>string</code> | Configure the current version of the app. This will be used for the first update request. If not set, the plugin will get the version from the native code. Only available for Android and iOS. | <code>undefined</code> | 4.17.48 |
|
|
241
|
+
| **`directUpdate`** | <code>boolean \| 'always' \| 'atInstall'</code> | Configure when the plugin should direct install updates. Only for autoUpdate mode. - false: Never do direct updates (default behavior) - atInstall: Direct update only when app is installed/updated from store, otherwise use normal background update - always: Always do direct updates immediately when available - true: (deprecated) Same as "always" for backward compatibility Only available for Android and iOS. | <code>false</code> | 5.1.0 |
|
|
242
|
+
| **`autoSplashscreen`** | <code>boolean</code> | Automatically handle splashscreen hiding when using directUpdate. When enabled, the plugin will automatically hide the splashscreen after updates are applied or when no update is needed. This removes the need to manually listen for appReady events and call SplashScreen.hide(). Only works when directUpdate is set to "atInstall", "always", or true. Requires the @capacitor/splash-screen plugin to be installed and configured with launchAutoHide: false. Only available for Android and iOS. | <code>false</code> | 7.6.0 |
|
|
243
|
+
| **`periodCheckDelay`** | <code>number</code> | Configure the delay period for period update check. the unit is in seconds. Only available for Android and iOS. Cannot be less than 600 seconds (10 minutes). | <code>600 // (10 minutes)</code> | |
|
|
244
|
+
| **`localS3`** | <code>boolean</code> | Configure the CLI to use a local server for testing or self-hosted update server. | <code>undefined</code> | 4.17.48 |
|
|
245
|
+
| **`localHost`** | <code>string</code> | Configure the CLI to use a local server for testing or self-hosted update server. | <code>undefined</code> | 4.17.48 |
|
|
246
|
+
| **`localWebHost`** | <code>string</code> | Configure the CLI to use a local server for testing or self-hosted update server. | <code>undefined</code> | 4.17.48 |
|
|
247
|
+
| **`localSupa`** | <code>string</code> | Configure the CLI to use a local server for testing or self-hosted update server. | <code>undefined</code> | 4.17.48 |
|
|
248
|
+
| **`localSupaAnon`** | <code>string</code> | Configure the CLI to use a local server for testing. | <code>undefined</code> | 4.17.48 |
|
|
249
|
+
| **`localApi`** | <code>string</code> | Configure the CLI to use a local api for testing. | <code>undefined</code> | 6.3.3 |
|
|
250
|
+
| **`localApiFiles`** | <code>string</code> | Configure the CLI to use a local file api for testing. | <code>undefined</code> | 6.3.3 |
|
|
251
|
+
| **`allowModifyUrl`** | <code>boolean</code> | Allow the plugin to modify the updateUrl, statsUrl and channelUrl dynamically from the JavaScript side. | <code>false</code> | 5.4.0 |
|
|
252
|
+
| **`defaultChannel`** | <code>string</code> | Set the default channel for the app in the config. Case sensitive. This will setting will override the default channel set in the cloud, but will still respect overrides made in the cloud. | <code>undefined</code> | 5.5.0 |
|
|
253
|
+
| **`appId`** | <code>string</code> | Configure the app id for the app in the config. | <code>undefined</code> | 6.0.0 |
|
|
254
|
+
| **`keepUrlPathAfterReload`** | <code>boolean</code> | Configure the plugin to keep the URL path after a reload. WARNING: When a reload is triggered, 'window.history' will be cleared. | <code>false</code> | 6.8.0 |
|
|
255
|
+
| **`disableJSLogging`** | <code>boolean</code> | Disable the JavaScript logging of the plugin. if true, the plugin will not log to the JavaScript console. only the native log will be done | <code>false</code> | 7.3.0 |
|
|
256
|
+
| **`shakeMenu`** | <code>boolean</code> | Enable shake gesture to show update menu for debugging/testing purposes | <code>false</code> | 7.5.0 |
|
|
255
257
|
|
|
256
258
|
### Examples
|
|
257
259
|
|
|
@@ -273,6 +275,7 @@ In `capacitor.config.json`:
|
|
|
273
275
|
"publicKey": undefined,
|
|
274
276
|
"version": undefined,
|
|
275
277
|
"directUpdate": undefined,
|
|
278
|
+
"autoSplashscreen": undefined,
|
|
276
279
|
"periodCheckDelay": undefined,
|
|
277
280
|
"localS3": undefined,
|
|
278
281
|
"localHost": undefined,
|
|
@@ -285,7 +288,8 @@ In `capacitor.config.json`:
|
|
|
285
288
|
"defaultChannel": undefined,
|
|
286
289
|
"appId": undefined,
|
|
287
290
|
"keepUrlPathAfterReload": undefined,
|
|
288
|
-
"disableJSLogging": undefined
|
|
291
|
+
"disableJSLogging": undefined,
|
|
292
|
+
"shakeMenu": undefined
|
|
289
293
|
}
|
|
290
294
|
}
|
|
291
295
|
}
|
|
@@ -313,6 +317,7 @@ const config: CapacitorConfig = {
|
|
|
313
317
|
publicKey: undefined,
|
|
314
318
|
version: undefined,
|
|
315
319
|
directUpdate: undefined,
|
|
320
|
+
autoSplashscreen: undefined,
|
|
316
321
|
periodCheckDelay: undefined,
|
|
317
322
|
localS3: undefined,
|
|
318
323
|
localHost: undefined,
|
|
@@ -326,6 +331,7 @@ const config: CapacitorConfig = {
|
|
|
326
331
|
appId: undefined,
|
|
327
332
|
keepUrlPathAfterReload: undefined,
|
|
328
333
|
disableJSLogging: undefined,
|
|
334
|
+
shakeMenu: undefined,
|
|
329
335
|
},
|
|
330
336
|
},
|
|
331
337
|
};
|
|
@@ -357,6 +363,7 @@ export default config;
|
|
|
357
363
|
* [`setChannel(...)`](#setchannel)
|
|
358
364
|
* [`unsetChannel(...)`](#unsetchannel)
|
|
359
365
|
* [`getChannel()`](#getchannel)
|
|
366
|
+
* [`listChannels()`](#listchannels)
|
|
360
367
|
* [`setCustomId(...)`](#setcustomid)
|
|
361
368
|
* [`getBuiltinVersion()`](#getbuiltinversion)
|
|
362
369
|
* [`getDeviceId()`](#getdeviceid)
|
|
@@ -374,6 +381,8 @@ export default config;
|
|
|
374
381
|
* [`addListener('appReady', ...)`](#addlistenerappready-)
|
|
375
382
|
* [`isAutoUpdateAvailable()`](#isautoupdateavailable)
|
|
376
383
|
* [`getNextBundle()`](#getnextbundle)
|
|
384
|
+
* [`setShakeMenu(...)`](#setshakemenu)
|
|
385
|
+
* [`isShakeMenuEnabled()`](#isshakemenuenabled)
|
|
377
386
|
* [Interfaces](#interfaces)
|
|
378
387
|
* [Type Aliases](#type-aliases)
|
|
379
388
|
|
|
@@ -678,6 +687,21 @@ Get the channel for this device
|
|
|
678
687
|
--------------------
|
|
679
688
|
|
|
680
689
|
|
|
690
|
+
### listChannels()
|
|
691
|
+
|
|
692
|
+
```typescript
|
|
693
|
+
listChannels() => Promise<ListChannelsResult>
|
|
694
|
+
```
|
|
695
|
+
|
|
696
|
+
List all channels available for this device that allow self-assignment
|
|
697
|
+
|
|
698
|
+
**Returns:** <code>Promise<<a href="#listchannelsresult">ListChannelsResult</a>></code>
|
|
699
|
+
|
|
700
|
+
**Since:** 7.5.0
|
|
701
|
+
|
|
702
|
+
--------------------
|
|
703
|
+
|
|
704
|
+
|
|
681
705
|
### setCustomId(...)
|
|
682
706
|
|
|
683
707
|
```typescript
|
|
@@ -972,6 +996,38 @@ Returns null if no next bundle is set.
|
|
|
972
996
|
--------------------
|
|
973
997
|
|
|
974
998
|
|
|
999
|
+
### setShakeMenu(...)
|
|
1000
|
+
|
|
1001
|
+
```typescript
|
|
1002
|
+
setShakeMenu(options: SetShakeMenuOptions) => Promise<void>
|
|
1003
|
+
```
|
|
1004
|
+
|
|
1005
|
+
Enable or disable the shake menu for debugging/testing purposes
|
|
1006
|
+
|
|
1007
|
+
| Param | Type | Description |
|
|
1008
|
+
| ------------- | ------------------------------------------------------------------- | -------------------------------------------------------- |
|
|
1009
|
+
| **`options`** | <code><a href="#setshakemenuoptions">SetShakeMenuOptions</a></code> | Contains enabled boolean to enable or disable shake menu |
|
|
1010
|
+
|
|
1011
|
+
**Since:** 7.5.0
|
|
1012
|
+
|
|
1013
|
+
--------------------
|
|
1014
|
+
|
|
1015
|
+
|
|
1016
|
+
### isShakeMenuEnabled()
|
|
1017
|
+
|
|
1018
|
+
```typescript
|
|
1019
|
+
isShakeMenuEnabled() => Promise<ShakeMenuEnabled>
|
|
1020
|
+
```
|
|
1021
|
+
|
|
1022
|
+
Get the current state of the shake menu
|
|
1023
|
+
|
|
1024
|
+
**Returns:** <code>Promise<<a href="#shakemenuenabled">ShakeMenuEnabled</a>></code>
|
|
1025
|
+
|
|
1026
|
+
**Since:** 7.5.0
|
|
1027
|
+
|
|
1028
|
+
--------------------
|
|
1029
|
+
|
|
1030
|
+
|
|
975
1031
|
### Interfaces
|
|
976
1032
|
|
|
977
1033
|
|
|
@@ -1145,6 +1201,23 @@ If you don't use backend, you need to provide the URL and version of the bundle.
|
|
|
1145
1201
|
| **`allowSet`** | <code>boolean</code> | | |
|
|
1146
1202
|
|
|
1147
1203
|
|
|
1204
|
+
#### ListChannelsResult
|
|
1205
|
+
|
|
1206
|
+
| Prop | Type | Description | Since |
|
|
1207
|
+
| -------------- | -------------------------- | -------------------------- | ----- |
|
|
1208
|
+
| **`channels`** | <code>ChannelInfo[]</code> | List of available channels | 7.5.0 |
|
|
1209
|
+
|
|
1210
|
+
|
|
1211
|
+
#### ChannelInfo
|
|
1212
|
+
|
|
1213
|
+
| Prop | Type | Description | Since |
|
|
1214
|
+
| -------------------- | -------------------- | ----------------------------------------------- | ----- |
|
|
1215
|
+
| **`id`** | <code>string</code> | The channel ID | 7.5.0 |
|
|
1216
|
+
| **`name`** | <code>string</code> | The channel name | 7.5.0 |
|
|
1217
|
+
| **`public`** | <code>boolean</code> | Whether this is a public channel | 7.5.0 |
|
|
1218
|
+
| **`allow_self_set`** | <code>boolean</code> | Whether devices can self-assign to this channel | 7.5.0 |
|
|
1219
|
+
|
|
1220
|
+
|
|
1148
1221
|
#### SetCustomIdOptions
|
|
1149
1222
|
|
|
1150
1223
|
| Prop | Type |
|
|
@@ -1252,6 +1325,20 @@ If you don't use backend, you need to provide the URL and version of the bundle.
|
|
|
1252
1325
|
| **`available`** | <code>boolean</code> |
|
|
1253
1326
|
|
|
1254
1327
|
|
|
1328
|
+
#### SetShakeMenuOptions
|
|
1329
|
+
|
|
1330
|
+
| Prop | Type |
|
|
1331
|
+
| ------------- | -------------------- |
|
|
1332
|
+
| **`enabled`** | <code>boolean</code> |
|
|
1333
|
+
|
|
1334
|
+
|
|
1335
|
+
#### ShakeMenuEnabled
|
|
1336
|
+
|
|
1337
|
+
| Prop | Type |
|
|
1338
|
+
| ------------- | -------------------- |
|
|
1339
|
+
| **`enabled`** | <code>boolean</code> |
|
|
1340
|
+
|
|
1341
|
+
|
|
1255
1342
|
### Type Aliases
|
|
1256
1343
|
|
|
1257
1344
|
|
|
@@ -60,7 +60,7 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
60
60
|
private static final String statsUrlDefault = "https://plugin.capgo.app/stats";
|
|
61
61
|
private static final String channelUrlDefault = "https://plugin.capgo.app/channel_self";
|
|
62
62
|
|
|
63
|
-
private final String PLUGIN_VERSION = "7.
|
|
63
|
+
private final String PLUGIN_VERSION = "7.6.0";
|
|
64
64
|
private static final String DELAY_CONDITION_PREFERENCES = "";
|
|
65
65
|
|
|
66
66
|
private SharedPreferences.Editor editor;
|
|
@@ -78,6 +78,10 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
78
78
|
private Thread backgroundTask;
|
|
79
79
|
private Boolean taskRunning = false;
|
|
80
80
|
private Boolean keepUrlPathAfterReload = false;
|
|
81
|
+
private Boolean autoSplashscreen = false;
|
|
82
|
+
private String directUpdateMode = "false";
|
|
83
|
+
private Boolean wasRecentlyInstalledOrUpdated = false;
|
|
84
|
+
Boolean shakeMenuEnabled = false;
|
|
81
85
|
|
|
82
86
|
private Boolean isPreviousMainActivity = true;
|
|
83
87
|
|
|
@@ -91,6 +95,8 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
91
95
|
|
|
92
96
|
private DelayUpdateUtils delayUpdateUtils;
|
|
93
97
|
|
|
98
|
+
private ShakeMenu shakeMenu;
|
|
99
|
+
|
|
94
100
|
private JSObject mapToJSObject(Map<String, Object> map) {
|
|
95
101
|
JSObject jsObject = new JSObject();
|
|
96
102
|
for (Map.Entry<String, Object> entry : map.entrySet()) {
|
|
@@ -154,7 +160,21 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
154
160
|
.readTimeout(this.implementation.timeout, TimeUnit.MILLISECONDS)
|
|
155
161
|
.writeTimeout(this.implementation.timeout, TimeUnit.MILLISECONDS)
|
|
156
162
|
.build();
|
|
157
|
-
|
|
163
|
+
// Handle directUpdate configuration - support string values and backward compatibility
|
|
164
|
+
String directUpdateConfig = this.getConfig().getString("directUpdate", null);
|
|
165
|
+
if (directUpdateConfig != null) {
|
|
166
|
+
this.directUpdateMode = directUpdateConfig;
|
|
167
|
+
this.implementation.directUpdate = directUpdateConfig.equals("always") || directUpdateConfig.equals("atInstall");
|
|
168
|
+
} else {
|
|
169
|
+
Boolean directUpdateBool = this.getConfig().getBoolean("directUpdate", false);
|
|
170
|
+
if (directUpdateBool) {
|
|
171
|
+
this.directUpdateMode = "always"; // backward compatibility: true = always
|
|
172
|
+
this.implementation.directUpdate = true;
|
|
173
|
+
} else {
|
|
174
|
+
this.directUpdateMode = "false";
|
|
175
|
+
this.implementation.directUpdate = false;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
158
178
|
this.currentVersionNative = new Version(this.getConfig().getString("version", pInfo.versionName));
|
|
159
179
|
this.delayUpdateUtils = new DelayUpdateUtils(
|
|
160
180
|
this.prefs,
|
|
@@ -223,9 +243,14 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
223
243
|
this.autoUpdate = this.getConfig().getBoolean("autoUpdate", true);
|
|
224
244
|
this.appReadyTimeout = this.getConfig().getInt("appReadyTimeout", 10000);
|
|
225
245
|
this.keepUrlPathAfterReload = this.getConfig().getBoolean("keepUrlPathAfterReload", false);
|
|
246
|
+
this.autoSplashscreen = this.getConfig().getBoolean("autoSplashscreen", false);
|
|
226
247
|
this.implementation.timeout = this.getConfig().getInt("responseTimeout", 20) * 1000;
|
|
248
|
+
this.shakeMenuEnabled = this.getConfig().getBoolean("shakeMenu", false);
|
|
227
249
|
boolean resetWhenUpdate = this.getConfig().getBoolean("resetWhenUpdate", true);
|
|
228
250
|
|
|
251
|
+
// Check if app was recently installed/updated BEFORE cleanupObsoleteVersions updates LatestVersionNative
|
|
252
|
+
this.wasRecentlyInstalledOrUpdated = this.checkIfRecentlyInstalledOrUpdated();
|
|
253
|
+
|
|
229
254
|
this.implementation.autoReset();
|
|
230
255
|
if (resetWhenUpdate) {
|
|
231
256
|
this.cleanupObsoleteVersions();
|
|
@@ -266,9 +291,66 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
266
291
|
semaphoreWait(CapacitorUpdaterPlugin.this.appReadyTimeout);
|
|
267
292
|
logger.info("semaphoreReady sendReadyToJs done");
|
|
268
293
|
CapacitorUpdaterPlugin.this.notifyListeners("appReady", ret);
|
|
294
|
+
|
|
295
|
+
// Auto hide splashscreen if enabled
|
|
296
|
+
if (CapacitorUpdaterPlugin.this.autoSplashscreen && CapacitorUpdaterPlugin.this.shouldUseDirectUpdate()) {
|
|
297
|
+
CapacitorUpdaterPlugin.this.hideSplashscreen();
|
|
298
|
+
}
|
|
269
299
|
});
|
|
270
300
|
}
|
|
271
301
|
|
|
302
|
+
private void hideSplashscreen() {
|
|
303
|
+
try {
|
|
304
|
+
// Create a simple PluginCall for the hide method
|
|
305
|
+
PluginCall call = new PluginCall(
|
|
306
|
+
null, // MessageHandler - can be null for this use case
|
|
307
|
+
"hideSplashscreen",
|
|
308
|
+
"hide",
|
|
309
|
+
"autoHideSplashscreen",
|
|
310
|
+
new JSObject()
|
|
311
|
+
);
|
|
312
|
+
|
|
313
|
+
// Use bridge's callPluginMethod to call SplashScreen.hide()
|
|
314
|
+
getBridge().callPluginMethod("SplashScreen", "hide", call);
|
|
315
|
+
logger.info("Splashscreen hidden automatically via callPluginMethod");
|
|
316
|
+
} catch (Exception e) {
|
|
317
|
+
logger.error("Error hiding splashscreen: " + e.getMessage());
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
private boolean checkIfRecentlyInstalledOrUpdated() {
|
|
322
|
+
String currentVersion = this.currentVersionNative.getOriginalString();
|
|
323
|
+
String lastKnownVersion = this.prefs.getString("LatestVersionNative", "");
|
|
324
|
+
|
|
325
|
+
if (lastKnownVersion.isEmpty()) {
|
|
326
|
+
// First time running, consider it as recently installed
|
|
327
|
+
return true;
|
|
328
|
+
} else if (!lastKnownVersion.equals(currentVersion)) {
|
|
329
|
+
// Version changed, consider it as recently updated
|
|
330
|
+
return true;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
return false;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
private boolean shouldUseDirectUpdate() {
|
|
337
|
+
switch (this.directUpdateMode) {
|
|
338
|
+
case "false":
|
|
339
|
+
return false;
|
|
340
|
+
case "always":
|
|
341
|
+
return true;
|
|
342
|
+
case "atInstall":
|
|
343
|
+
if (this.wasRecentlyInstalledOrUpdated) {
|
|
344
|
+
// Reset the flag after first use to prevent subsequent foreground events from using direct update
|
|
345
|
+
this.wasRecentlyInstalledOrUpdated = false;
|
|
346
|
+
return true;
|
|
347
|
+
}
|
|
348
|
+
return false;
|
|
349
|
+
default:
|
|
350
|
+
return false;
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
272
354
|
private void directUpdateFinish(final BundleInfo latest) {
|
|
273
355
|
CapacitorUpdaterPlugin.this.implementation.set(latest);
|
|
274
356
|
CapacitorUpdaterPlugin.this._reload();
|
|
@@ -438,7 +520,14 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
438
520
|
CapacitorUpdaterPlugin.this.implementation.unsetChannel(res -> {
|
|
439
521
|
JSObject jsRes = mapToJSObject(res);
|
|
440
522
|
if (jsRes.has("error")) {
|
|
441
|
-
|
|
523
|
+
String errorMessage = jsRes.has("message") ? jsRes.getString("message") : jsRes.getString("error");
|
|
524
|
+
String errorCode = jsRes.getString("error");
|
|
525
|
+
|
|
526
|
+
JSObject errorObj = new JSObject();
|
|
527
|
+
errorObj.put("message", errorMessage);
|
|
528
|
+
errorObj.put("error", errorCode);
|
|
529
|
+
|
|
530
|
+
call.reject(errorMessage, "UNSETCHANNEL_FAILED", null, errorObj);
|
|
442
531
|
} else {
|
|
443
532
|
if (CapacitorUpdaterPlugin.this._isAutoUpdateEnabled() && Boolean.TRUE.equals(triggerAutoUpdate)) {
|
|
444
533
|
logger.info("Calling autoupdater after channel change!");
|
|
@@ -461,7 +550,10 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
461
550
|
|
|
462
551
|
if (channel == null) {
|
|
463
552
|
logger.error("setChannel called without channel");
|
|
464
|
-
|
|
553
|
+
JSObject errorObj = new JSObject();
|
|
554
|
+
errorObj.put("message", "setChannel called without channel");
|
|
555
|
+
errorObj.put("error", "missing_parameter");
|
|
556
|
+
call.reject("setChannel called without channel", "SETCHANNEL_INVALID_PARAMS", null, errorObj);
|
|
465
557
|
return;
|
|
466
558
|
}
|
|
467
559
|
try {
|
|
@@ -470,7 +562,14 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
470
562
|
CapacitorUpdaterPlugin.this.implementation.setChannel(channel, res -> {
|
|
471
563
|
JSObject jsRes = mapToJSObject(res);
|
|
472
564
|
if (jsRes.has("error")) {
|
|
473
|
-
|
|
565
|
+
String errorMessage = jsRes.has("message") ? jsRes.getString("message") : jsRes.getString("error");
|
|
566
|
+
String errorCode = jsRes.getString("error");
|
|
567
|
+
|
|
568
|
+
JSObject errorObj = new JSObject();
|
|
569
|
+
errorObj.put("message", errorMessage);
|
|
570
|
+
errorObj.put("error", errorCode);
|
|
571
|
+
|
|
572
|
+
call.reject(errorMessage, "SETCHANNEL_FAILED", null, errorObj);
|
|
474
573
|
} else {
|
|
475
574
|
if (CapacitorUpdaterPlugin.this._isAutoUpdateEnabled() && Boolean.TRUE.equals(triggerAutoUpdate)) {
|
|
476
575
|
logger.info("Calling autoupdater after channel change!");
|
|
@@ -494,7 +593,14 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
494
593
|
CapacitorUpdaterPlugin.this.implementation.getChannel(res -> {
|
|
495
594
|
JSObject jsRes = mapToJSObject(res);
|
|
496
595
|
if (jsRes.has("error")) {
|
|
497
|
-
|
|
596
|
+
String errorMessage = jsRes.has("message") ? jsRes.getString("message") : jsRes.getString("error");
|
|
597
|
+
String errorCode = jsRes.getString("error");
|
|
598
|
+
|
|
599
|
+
JSObject errorObj = new JSObject();
|
|
600
|
+
errorObj.put("message", errorMessage);
|
|
601
|
+
errorObj.put("error", errorCode);
|
|
602
|
+
|
|
603
|
+
call.reject(errorMessage, "GETCHANNEL_FAILED", null, errorObj);
|
|
498
604
|
} else {
|
|
499
605
|
call.resolve(jsRes);
|
|
500
606
|
}
|
|
@@ -506,6 +612,33 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
506
612
|
}
|
|
507
613
|
}
|
|
508
614
|
|
|
615
|
+
@PluginMethod
|
|
616
|
+
public void listChannels(final PluginCall call) {
|
|
617
|
+
try {
|
|
618
|
+
logger.info("listChannels");
|
|
619
|
+
startNewThread(() ->
|
|
620
|
+
CapacitorUpdaterPlugin.this.implementation.listChannels(res -> {
|
|
621
|
+
JSObject jsRes = mapToJSObject(res);
|
|
622
|
+
if (jsRes.has("error")) {
|
|
623
|
+
String errorMessage = jsRes.has("message") ? jsRes.getString("message") : jsRes.getString("error");
|
|
624
|
+
String errorCode = jsRes.getString("error");
|
|
625
|
+
|
|
626
|
+
JSObject errorObj = new JSObject();
|
|
627
|
+
errorObj.put("message", errorMessage);
|
|
628
|
+
errorObj.put("error", errorCode);
|
|
629
|
+
|
|
630
|
+
call.reject(errorMessage, "LISTCHANNELS_FAILED", null, errorObj);
|
|
631
|
+
} else {
|
|
632
|
+
call.resolve(jsRes);
|
|
633
|
+
}
|
|
634
|
+
})
|
|
635
|
+
);
|
|
636
|
+
} catch (final Exception e) {
|
|
637
|
+
logger.error("Failed to listChannels: " + e.getMessage());
|
|
638
|
+
call.reject("Failed to listChannels", e);
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
|
|
509
642
|
@PluginMethod
|
|
510
643
|
public void download(final PluginCall call) {
|
|
511
644
|
final String url = call.getString("url");
|
|
@@ -994,9 +1127,8 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
994
1127
|
}
|
|
995
1128
|
|
|
996
1129
|
private Thread backgroundDownload() {
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
: "Update will occur next time app moves to background.";
|
|
1130
|
+
boolean shouldDirectUpdate = this.shouldUseDirectUpdate();
|
|
1131
|
+
String messageUpdate = shouldDirectUpdate ? "Update will occur now." : "Update will occur next time app moves to background.";
|
|
1000
1132
|
return startNewThread(() -> {
|
|
1001
1133
|
logger.info("Check for update via: " + CapacitorUpdaterPlugin.this.updateUrl);
|
|
1002
1134
|
CapacitorUpdaterPlugin.this.implementation.getLatest(CapacitorUpdaterPlugin.this.updateUrl, null, res -> {
|
|
@@ -1023,7 +1155,7 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
1023
1155
|
|
|
1024
1156
|
if ("builtin".equals(latestVersionName)) {
|
|
1025
1157
|
logger.info("Latest version is builtin");
|
|
1026
|
-
if (
|
|
1158
|
+
if (shouldDirectUpdate) {
|
|
1027
1159
|
logger.info("Direct update to builtin version");
|
|
1028
1160
|
this._reset(false);
|
|
1029
1161
|
CapacitorUpdaterPlugin.this.endBackGroundTaskWithNotif(
|
|
@@ -1075,7 +1207,7 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
1075
1207
|
}
|
|
1076
1208
|
if (latest.isDownloaded()) {
|
|
1077
1209
|
logger.info("Latest bundle already exists and download is NOT required. " + messageUpdate);
|
|
1078
|
-
if (
|
|
1210
|
+
if (shouldDirectUpdate) {
|
|
1079
1211
|
Gson gson = new Gson();
|
|
1080
1212
|
String delayUpdatePreferences = prefs.getString(DelayUpdateUtils.DELAY_CONDITION_PREFERENCES, "[]");
|
|
1081
1213
|
Type type = new TypeToken<ArrayList<DelayCondition>>() {}.getType();
|
|
@@ -1328,6 +1460,16 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
1328
1460
|
}
|
|
1329
1461
|
logger.info("onActivityStarted " + getActivity().getClass().getName());
|
|
1330
1462
|
isPreviousMainActivity = true;
|
|
1463
|
+
|
|
1464
|
+
// Initialize shake menu if enabled and activity is BridgeActivity
|
|
1465
|
+
if (shakeMenuEnabled && getActivity() instanceof com.getcapacitor.BridgeActivity && shakeMenu == null) {
|
|
1466
|
+
try {
|
|
1467
|
+
shakeMenu = new ShakeMenu(this, (com.getcapacitor.BridgeActivity) getActivity(), logger);
|
|
1468
|
+
logger.info("Shake menu initialized");
|
|
1469
|
+
} catch (Exception e) {
|
|
1470
|
+
logger.error("Failed to initialize shake menu: " + e.getMessage());
|
|
1471
|
+
}
|
|
1472
|
+
}
|
|
1331
1473
|
}
|
|
1332
1474
|
|
|
1333
1475
|
@Override
|
|
@@ -1359,5 +1501,61 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
1359
1501
|
if (counterActivityCreate == 0) {
|
|
1360
1502
|
this.appKilled();
|
|
1361
1503
|
}
|
|
1504
|
+
|
|
1505
|
+
// Clean up shake menu
|
|
1506
|
+
if (shakeMenu != null) {
|
|
1507
|
+
try {
|
|
1508
|
+
shakeMenu.stop();
|
|
1509
|
+
shakeMenu = null;
|
|
1510
|
+
logger.info("Shake menu cleaned up");
|
|
1511
|
+
} catch (Exception e) {
|
|
1512
|
+
logger.error("Failed to clean up shake menu: " + e.getMessage());
|
|
1513
|
+
}
|
|
1514
|
+
}
|
|
1515
|
+
}
|
|
1516
|
+
|
|
1517
|
+
@PluginMethod
|
|
1518
|
+
public void setShakeMenu(final PluginCall call) {
|
|
1519
|
+
final Boolean enabled = call.getBoolean("enabled");
|
|
1520
|
+
if (enabled == null) {
|
|
1521
|
+
logger.error("setShakeMenu called without enabled parameter");
|
|
1522
|
+
call.reject("setShakeMenu called without enabled parameter");
|
|
1523
|
+
return;
|
|
1524
|
+
}
|
|
1525
|
+
|
|
1526
|
+
this.shakeMenuEnabled = enabled;
|
|
1527
|
+
logger.info("Shake menu " + (enabled ? "enabled" : "disabled"));
|
|
1528
|
+
|
|
1529
|
+
// Manage shake menu instance based on enabled state
|
|
1530
|
+
if (enabled && getActivity() instanceof com.getcapacitor.BridgeActivity && shakeMenu == null) {
|
|
1531
|
+
try {
|
|
1532
|
+
shakeMenu = new ShakeMenu(this, (com.getcapacitor.BridgeActivity) getActivity(), logger);
|
|
1533
|
+
logger.info("Shake menu initialized");
|
|
1534
|
+
} catch (Exception e) {
|
|
1535
|
+
logger.error("Failed to initialize shake menu: " + e.getMessage());
|
|
1536
|
+
}
|
|
1537
|
+
} else if (!enabled && shakeMenu != null) {
|
|
1538
|
+
try {
|
|
1539
|
+
shakeMenu.stop();
|
|
1540
|
+
shakeMenu = null;
|
|
1541
|
+
logger.info("Shake menu stopped");
|
|
1542
|
+
} catch (Exception e) {
|
|
1543
|
+
logger.error("Failed to stop shake menu: " + e.getMessage());
|
|
1544
|
+
}
|
|
1545
|
+
}
|
|
1546
|
+
|
|
1547
|
+
call.resolve();
|
|
1548
|
+
}
|
|
1549
|
+
|
|
1550
|
+
@PluginMethod
|
|
1551
|
+
public void isShakeMenuEnabled(final PluginCall call) {
|
|
1552
|
+
try {
|
|
1553
|
+
final JSObject ret = new JSObject();
|
|
1554
|
+
ret.put("enabled", this.shakeMenuEnabled);
|
|
1555
|
+
call.resolve(ret);
|
|
1556
|
+
} catch (final Exception e) {
|
|
1557
|
+
logger.error("Could not get shake menu status " + e.getMessage());
|
|
1558
|
+
call.reject("Could not get shake menu status", e);
|
|
1559
|
+
}
|
|
1362
1560
|
}
|
|
1363
1561
|
}
|