@capgo/capacitor-updater 8.0.0-alpha → 8.0.0-alpha.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 +102 -12
- package/android/build.gradle +3 -3
- package/android/src/main/java/ee/forgr/capacitor_updater/BundleInfo.java +60 -8
- package/android/src/main/java/ee/forgr/capacitor_updater/CapacitorUpdaterPlugin.java +75 -36
- package/android/src/main/java/ee/forgr/capacitor_updater/CapgoUpdater.java +41 -104
- package/android/src/main/java/ee/forgr/capacitor_updater/DownloadService.java +84 -75
- package/dist/docs.json +105 -8
- package/dist/esm/definitions.d.ts +97 -1
- package/dist/esm/definitions.js.map +1 -1
- package/ios/Sources/CapacitorUpdaterPlugin/BundleInfo.swift +37 -10
- package/ios/Sources/CapacitorUpdaterPlugin/CapacitorUpdaterPlugin.swift +26 -8
- package/ios/Sources/CapacitorUpdaterPlugin/CapgoUpdater.swift +68 -71
- package/ios/Sources/CapacitorUpdaterPlugin/InternalUtils.swift +4 -0
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -68,6 +68,16 @@ Join the [discord](https://discord.gg/VnYRvBfgA6) to get help.
|
|
|
68
68
|
|
|
69
69
|
## Migration to v8
|
|
70
70
|
|
|
71
|
+
## Migration to v7.34
|
|
72
|
+
|
|
73
|
+
- **Channel storage change**: `setChannel()` now stores channel assignments locally on the device instead of in the cloud. This provides better offline support and reduces backend load.
|
|
74
|
+
- Channel assignments persist between app restarts
|
|
75
|
+
- Use `unsetChannel()` to clear the local assignment and revert to `defaultChannel`
|
|
76
|
+
- Old devices (< v7.34.0) will continue using cloud-based storage
|
|
77
|
+
- **New event**: Listen to the `channelPrivate` event to handle cases where a user tries to assign themselves to a private channel (one that doesn't allow self-assignment). See example in the `setChannel()` documentation above.
|
|
78
|
+
|
|
79
|
+
## Migration to v7
|
|
80
|
+
|
|
71
81
|
The min version of IOS is now 15.5 instead of 15 as Capacitor 8 requirement.
|
|
72
82
|
This is due to bump of ZipArchive to latest, a key dependency of this project is the zlib library. zlib before version 1.2.12 allows memory corruption when deflating (i.e., when compressing) if the input has many distant matches according to [CVE-2018-25032](https://nvd.nist.gov/vuln/detail/cve-2018-25032).
|
|
73
83
|
zlib is a native library so we need to bump the minimum iOS version to 15.5 as ZipArchive did the same in their latest versions.
|
|
@@ -273,6 +283,7 @@ CapacitorUpdater can be configured with these options:
|
|
|
273
283
|
| **`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 |
|
|
274
284
|
| **`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 |
|
|
275
285
|
| **`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 |
|
|
286
|
+
| **`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 |
|
|
276
287
|
| **`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 |
|
|
277
288
|
| **`appId`** | <code>string</code> | Configure the app id for the app in the config. | <code>undefined</code> | 6.0.0 |
|
|
278
289
|
| **`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 |
|
|
@@ -315,6 +326,7 @@ In `capacitor.config.json`:
|
|
|
315
326
|
"allowManualBundleError": undefined,
|
|
316
327
|
"persistCustomId": undefined,
|
|
317
328
|
"persistModifyUrl": undefined,
|
|
329
|
+
"allowSetDefaultChannel": undefined,
|
|
318
330
|
"defaultChannel": undefined,
|
|
319
331
|
"appId": undefined,
|
|
320
332
|
"keepUrlPathAfterReload": undefined,
|
|
@@ -363,6 +375,7 @@ const config: CapacitorConfig = {
|
|
|
363
375
|
allowManualBundleError: undefined,
|
|
364
376
|
persistCustomId: undefined,
|
|
365
377
|
persistModifyUrl: undefined,
|
|
378
|
+
allowSetDefaultChannel: undefined,
|
|
366
379
|
defaultChannel: undefined,
|
|
367
380
|
appId: undefined,
|
|
368
381
|
keepUrlPathAfterReload: undefined,
|
|
@@ -418,6 +431,7 @@ export default config;
|
|
|
418
431
|
* [`addListener('downloadFailed', ...)`](#addlistenerdownloadfailed-)
|
|
419
432
|
* [`addListener('appReloaded', ...)`](#addlistenerappreloaded-)
|
|
420
433
|
* [`addListener('appReady', ...)`](#addlistenerappready-)
|
|
434
|
+
* [`addListener('channelPrivate', ...)`](#addlistenerchannelprivate-)
|
|
421
435
|
* [`isAutoUpdateAvailable()`](#isautoupdateavailable)
|
|
422
436
|
* [`getNextBundle()`](#getnextbundle)
|
|
423
437
|
* [`getFailedUpdate()`](#getfailedupdate)
|
|
@@ -865,6 +879,34 @@ After receiving the latest version info, you can:
|
|
|
865
879
|
2. Download it using {@link download}
|
|
866
880
|
3. Apply it using {@link next} or {@link set}
|
|
867
881
|
|
|
882
|
+
**Important: Error handling for "no new version available"**
|
|
883
|
+
|
|
884
|
+
When the device's current version matches the latest version on the server (i.e., the device is already
|
|
885
|
+
up-to-date), the server returns a 200 response with `error: "no_new_version_available"` and
|
|
886
|
+
`message: "No new version available"`. **This causes `getLatest()` to throw an error**, even though
|
|
887
|
+
this is a normal, expected condition.
|
|
888
|
+
|
|
889
|
+
You should catch this specific error to handle it gracefully:
|
|
890
|
+
|
|
891
|
+
```typescript
|
|
892
|
+
try {
|
|
893
|
+
const latest = await CapacitorUpdater.getLatest();
|
|
894
|
+
// New version is available, proceed with download
|
|
895
|
+
} catch (error) {
|
|
896
|
+
if (error.message === 'No new version available') {
|
|
897
|
+
// Device is already on the latest version - this is normal
|
|
898
|
+
console.log('Already up to date');
|
|
899
|
+
} else {
|
|
900
|
+
// Actual error occurred
|
|
901
|
+
console.error('Failed to check for updates:', error);
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
```
|
|
905
|
+
|
|
906
|
+
In this scenario, the server:
|
|
907
|
+
- Logs the request with a "No new version available" message
|
|
908
|
+
- Sends a "noNew" stat action to track that the device checked for updates but was already current (done on the backend)
|
|
909
|
+
|
|
868
910
|
| Param | Type | Description |
|
|
869
911
|
| ------------- | ------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
|
|
870
912
|
| **`options`** | <code><a href="#getlatestoptions">GetLatestOptions</a></code> | Optional {@link <a href="#getlatestoptions">GetLatestOptions</a>} to specify which channel to check. |
|
|
@@ -900,6 +942,19 @@ Channels allow you to distribute different bundle versions to different groups o
|
|
|
900
942
|
- At app boot/initialization - use {@link PluginsConfig.CapacitorUpdater.defaultChannel} config instead
|
|
901
943
|
- Before user interaction
|
|
902
944
|
|
|
945
|
+
**Important: Listen for the `channelPrivate` event**
|
|
946
|
+
|
|
947
|
+
When a user attempts to set a channel that doesn't allow device self-assignment, the method will
|
|
948
|
+
throw an error AND fire a {@link addListener}('channelPrivate') event. You should listen to this event
|
|
949
|
+
to provide appropriate feedback to users:
|
|
950
|
+
|
|
951
|
+
```typescript
|
|
952
|
+
CapacitorUpdater.addListener('channelPrivate', (data) => {
|
|
953
|
+
console.warn(`Cannot access channel "${data.channel}": ${data.message}`);
|
|
954
|
+
// Show user-friendly message
|
|
955
|
+
});
|
|
956
|
+
```
|
|
957
|
+
|
|
903
958
|
This sends a request to the Capgo backend linking your device ID to the specified channel.
|
|
904
959
|
|
|
905
960
|
| Param | Type | Description |
|
|
@@ -1364,6 +1419,31 @@ Listen for app ready event in the App, let you know when app is ready to use, th
|
|
|
1364
1419
|
--------------------
|
|
1365
1420
|
|
|
1366
1421
|
|
|
1422
|
+
#### addListener('channelPrivate', ...)
|
|
1423
|
+
|
|
1424
|
+
```typescript
|
|
1425
|
+
addListener(eventName: 'channelPrivate', listenerFunc: (state: ChannelPrivateEvent) => void) => Promise<PluginListenerHandle>
|
|
1426
|
+
```
|
|
1427
|
+
|
|
1428
|
+
Listen for channel private event, fired when attempting to set a channel that doesn't allow device self-assignment.
|
|
1429
|
+
|
|
1430
|
+
This event is useful for:
|
|
1431
|
+
- Informing users they don't have permission to switch to a specific channel
|
|
1432
|
+
- Implementing custom error handling for channel restrictions
|
|
1433
|
+
- Logging unauthorized channel access attempts
|
|
1434
|
+
|
|
1435
|
+
| Param | Type |
|
|
1436
|
+
| ------------------ | --------------------------------------------------------------------------------------- |
|
|
1437
|
+
| **`eventName`** | <code>'channelPrivate'</code> |
|
|
1438
|
+
| **`listenerFunc`** | <code>(state: <a href="#channelprivateevent">ChannelPrivateEvent</a>) => void</code> |
|
|
1439
|
+
|
|
1440
|
+
**Returns:** <code>Promise<<a href="#pluginlistenerhandle">PluginListenerHandle</a>></code>
|
|
1441
|
+
|
|
1442
|
+
**Since:** 7.34.0
|
|
1443
|
+
|
|
1444
|
+
--------------------
|
|
1445
|
+
|
|
1446
|
+
|
|
1367
1447
|
#### isAutoUpdateAvailable()
|
|
1368
1448
|
|
|
1369
1449
|
```typescript
|
|
@@ -1680,18 +1760,20 @@ If you don't use backend, you need to provide the URL and version of the bundle.
|
|
|
1680
1760
|
|
|
1681
1761
|
##### LatestVersion
|
|
1682
1762
|
|
|
1683
|
-
| Prop | Type | Description
|
|
1684
|
-
| ---------------- | ---------------------------- |
|
|
1685
|
-
| **`version`** | <code>string</code> | Result of getLatest method
|
|
1686
|
-
| **`checksum`** | <code>string</code> |
|
|
1687
|
-
| **`breaking`** | <code>boolean</code> | Indicates whether the update was flagged as breaking by the backend.
|
|
1688
|
-
| **`major`** | <code>boolean</code> |
|
|
1689
|
-
| **`message`** | <code>string</code> |
|
|
1690
|
-
| **`sessionKey`** | <code>string</code> |
|
|
1691
|
-
| **`error`** | <code>string</code> |
|
|
1692
|
-
| **`old`** | <code>string</code> |
|
|
1693
|
-
| **`url`** | <code>string</code> |
|
|
1694
|
-
| **`manifest`** | <code>ManifestEntry[]</code> |
|
|
1763
|
+
| Prop | Type | Description | Since |
|
|
1764
|
+
| ---------------- | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------ |
|
|
1765
|
+
| **`version`** | <code>string</code> | Result of getLatest method | 4.0.0 |
|
|
1766
|
+
| **`checksum`** | <code>string</code> | | 6 |
|
|
1767
|
+
| **`breaking`** | <code>boolean</code> | Indicates whether the update was flagged as breaking by the backend. | 7.22.0 |
|
|
1768
|
+
| **`major`** | <code>boolean</code> | | |
|
|
1769
|
+
| **`message`** | <code>string</code> | Optional message from the server. When no new version is available, this will be "No new version available". | |
|
|
1770
|
+
| **`sessionKey`** | <code>string</code> | | |
|
|
1771
|
+
| **`error`** | <code>string</code> | Error code from the server, if any. Common values: - `"no_new_version_available"`: Device is already on the latest version (not a failure) - Other error codes indicate actual failures in the update process | |
|
|
1772
|
+
| **`old`** | <code>string</code> | The previous/current version name (provided for reference). | |
|
|
1773
|
+
| **`url`** | <code>string</code> | Download URL for the bundle (when a new version is available). | |
|
|
1774
|
+
| **`manifest`** | <code>ManifestEntry[]</code> | File list for partial updates (when using multi-file downloads). | 6.1 |
|
|
1775
|
+
| **`link`** | <code>string</code> | Optional link associated with this bundle version (e.g., release notes URL, changelog, GitHub release). | 7.35.0 |
|
|
1776
|
+
| **`comment`** | <code>string</code> | Optional comment or description for this bundle version. | 7.35.0 |
|
|
1695
1777
|
|
|
1696
1778
|
|
|
1697
1779
|
##### GetLatestOptions
|
|
@@ -1853,6 +1935,14 @@ If you don't use backend, you need to provide the URL and version of the bundle.
|
|
|
1853
1935
|
| **`status`** | <code>string</code> | | |
|
|
1854
1936
|
|
|
1855
1937
|
|
|
1938
|
+
##### ChannelPrivateEvent
|
|
1939
|
+
|
|
1940
|
+
| Prop | Type | Description | Since |
|
|
1941
|
+
| ------------- | ------------------- | ----------------------------------------------------------------------------------- | ------ |
|
|
1942
|
+
| **`channel`** | <code>string</code> | Emitted when attempting to set a channel that doesn't allow device self-assignment. | 7.34.0 |
|
|
1943
|
+
| **`message`** | <code>string</code> | | |
|
|
1944
|
+
|
|
1945
|
+
|
|
1856
1946
|
##### AutoUpdateAvailable
|
|
1857
1947
|
|
|
1858
1948
|
| Prop | Type |
|
package/android/build.gradle
CHANGED
|
@@ -49,16 +49,16 @@ repositories {
|
|
|
49
49
|
|
|
50
50
|
|
|
51
51
|
dependencies {
|
|
52
|
-
def work_version = "2.
|
|
52
|
+
def work_version = "2.10.5"
|
|
53
53
|
implementation "androidx.work:work-runtime:$work_version"
|
|
54
54
|
implementation "com.google.android.gms:play-services-tasks:18.4.0"
|
|
55
|
-
implementation "com.google.guava:guava:33.
|
|
55
|
+
implementation "com.google.guava:guava:33.5.0-android"
|
|
56
56
|
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
|
57
57
|
implementation project(':capacitor-android')
|
|
58
58
|
implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion"
|
|
59
59
|
implementation 'io.github.g00fy2:versioncompare:1.5.0'
|
|
60
60
|
testImplementation "junit:junit:$junitVersion"
|
|
61
|
-
testImplementation 'org.mockito:mockito-core:5.
|
|
61
|
+
testImplementation 'org.mockito:mockito-core:5.20.0'
|
|
62
62
|
testImplementation 'org.json:json:20250517'
|
|
63
63
|
testImplementation 'org.robolectric:robolectric:4.13'
|
|
64
64
|
androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion"
|
|
@@ -29,25 +29,53 @@ public class BundleInfo {
|
|
|
29
29
|
private final String version;
|
|
30
30
|
private final String checksum;
|
|
31
31
|
private final BundleStatus status;
|
|
32
|
+
private final String link;
|
|
33
|
+
private final String comment;
|
|
32
34
|
|
|
33
35
|
static {
|
|
34
36
|
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
|
|
35
37
|
}
|
|
36
38
|
|
|
37
39
|
public BundleInfo(final BundleInfo source) {
|
|
38
|
-
this(source.id, source.version, source.status, source.downloaded, source.checksum);
|
|
40
|
+
this(source.id, source.version, source.status, source.downloaded, source.checksum, source.link, source.comment);
|
|
39
41
|
}
|
|
40
42
|
|
|
41
43
|
public BundleInfo(final String id, final String version, final BundleStatus status, final Date downloaded, final String checksum) {
|
|
42
|
-
this(id, version, status, sdf.format(downloaded), checksum);
|
|
44
|
+
this(id, version, status, sdf.format(downloaded), checksum, null, null);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
public BundleInfo(
|
|
48
|
+
final String id,
|
|
49
|
+
final String version,
|
|
50
|
+
final BundleStatus status,
|
|
51
|
+
final Date downloaded,
|
|
52
|
+
final String checksum,
|
|
53
|
+
final String link,
|
|
54
|
+
final String comment
|
|
55
|
+
) {
|
|
56
|
+
this(id, version, status, sdf.format(downloaded), checksum, link, comment);
|
|
43
57
|
}
|
|
44
58
|
|
|
45
59
|
public BundleInfo(final String id, final String version, final BundleStatus status, final String downloaded, final String checksum) {
|
|
60
|
+
this(id, version, status, downloaded, checksum, null, null);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
public BundleInfo(
|
|
64
|
+
final String id,
|
|
65
|
+
final String version,
|
|
66
|
+
final BundleStatus status,
|
|
67
|
+
final String downloaded,
|
|
68
|
+
final String checksum,
|
|
69
|
+
final String link,
|
|
70
|
+
final String comment
|
|
71
|
+
) {
|
|
46
72
|
this.downloaded = downloaded != null ? downloaded.trim() : "";
|
|
47
73
|
this.id = id != null ? id : "";
|
|
48
74
|
this.version = version;
|
|
49
75
|
this.checksum = checksum != null ? checksum : "";
|
|
50
76
|
this.status = status != null ? status : BundleStatus.ERROR;
|
|
77
|
+
this.link = link;
|
|
78
|
+
this.comment = comment;
|
|
51
79
|
}
|
|
52
80
|
|
|
53
81
|
public Boolean isBuiltin() {
|
|
@@ -75,7 +103,7 @@ public class BundleInfo {
|
|
|
75
103
|
}
|
|
76
104
|
|
|
77
105
|
public BundleInfo setDownloaded(Date downloaded) {
|
|
78
|
-
return new BundleInfo(this.id, this.version, this.status, downloaded, this.checksum);
|
|
106
|
+
return new BundleInfo(this.id, this.version, this.status, downloaded, this.checksum, this.link, this.comment);
|
|
79
107
|
}
|
|
80
108
|
|
|
81
109
|
public String getChecksum() {
|
|
@@ -83,7 +111,7 @@ public class BundleInfo {
|
|
|
83
111
|
}
|
|
84
112
|
|
|
85
113
|
public BundleInfo setChecksum(String checksum) {
|
|
86
|
-
return new BundleInfo(this.id, this.version, this.status, this.downloaded, checksum);
|
|
114
|
+
return new BundleInfo(this.id, this.version, this.status, this.downloaded, checksum, this.link, this.comment);
|
|
87
115
|
}
|
|
88
116
|
|
|
89
117
|
public String getId() {
|
|
@@ -91,7 +119,7 @@ public class BundleInfo {
|
|
|
91
119
|
}
|
|
92
120
|
|
|
93
121
|
public BundleInfo setId(String id) {
|
|
94
|
-
return new BundleInfo(id, this.version, this.status, this.downloaded, this.checksum);
|
|
122
|
+
return new BundleInfo(id, this.version, this.status, this.downloaded, this.checksum, this.link, this.comment);
|
|
95
123
|
}
|
|
96
124
|
|
|
97
125
|
public String getVersionName() {
|
|
@@ -99,7 +127,7 @@ public class BundleInfo {
|
|
|
99
127
|
}
|
|
100
128
|
|
|
101
129
|
public BundleInfo setVersionName(String version) {
|
|
102
|
-
return new BundleInfo(this.id, version, this.status, this.downloaded, this.checksum);
|
|
130
|
+
return new BundleInfo(this.id, version, this.status, this.downloaded, this.checksum, this.link, this.comment);
|
|
103
131
|
}
|
|
104
132
|
|
|
105
133
|
public BundleStatus getStatus() {
|
|
@@ -110,7 +138,23 @@ public class BundleInfo {
|
|
|
110
138
|
}
|
|
111
139
|
|
|
112
140
|
public BundleInfo setStatus(BundleStatus status) {
|
|
113
|
-
return new BundleInfo(this.id, this.version, status, this.downloaded, this.checksum);
|
|
141
|
+
return new BundleInfo(this.id, this.version, status, this.downloaded, this.checksum, this.link, this.comment);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
public String getLink() {
|
|
145
|
+
return this.link;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
public BundleInfo setLink(String link) {
|
|
149
|
+
return new BundleInfo(this.id, this.version, this.status, this.downloaded, this.checksum, link, this.comment);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
public String getComment() {
|
|
153
|
+
return this.comment;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
public BundleInfo setComment(String comment) {
|
|
157
|
+
return new BundleInfo(this.id, this.version, this.status, this.downloaded, this.checksum, this.link, comment);
|
|
114
158
|
}
|
|
115
159
|
|
|
116
160
|
public static BundleInfo fromJSON(final String jsonString) throws JSONException {
|
|
@@ -120,7 +164,9 @@ public class BundleInfo {
|
|
|
120
164
|
json.has("version") ? json.getString("version") : BundleInfo.VERSION_UNKNOWN,
|
|
121
165
|
json.has("status") ? BundleStatus.fromString(json.getString("status")) : BundleStatus.PENDING,
|
|
122
166
|
json.has("downloaded") ? json.getString("downloaded") : "",
|
|
123
|
-
json.has("checksum") ? json.getString("checksum") : ""
|
|
167
|
+
json.has("checksum") ? json.getString("checksum") : "",
|
|
168
|
+
json.has("link") ? json.getString("link") : null,
|
|
169
|
+
json.has("comment") ? json.getString("comment") : null
|
|
124
170
|
);
|
|
125
171
|
}
|
|
126
172
|
|
|
@@ -131,6 +177,12 @@ public class BundleInfo {
|
|
|
131
177
|
result.put("downloaded", this.getDownloaded());
|
|
132
178
|
result.put("checksum", this.getChecksum());
|
|
133
179
|
result.put("status", this.getStatus().toString());
|
|
180
|
+
if (this.link != null && !this.link.isEmpty()) {
|
|
181
|
+
result.put("link", this.link);
|
|
182
|
+
}
|
|
183
|
+
if (this.comment != null && !this.comment.isEmpty()) {
|
|
184
|
+
result.put("comment", this.comment);
|
|
185
|
+
}
|
|
134
186
|
return result;
|
|
135
187
|
}
|
|
136
188
|
|
|
@@ -68,10 +68,11 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
68
68
|
private static final String UPDATE_URL_PREF_KEY = "CapacitorUpdater.updateUrl";
|
|
69
69
|
private static final String STATS_URL_PREF_KEY = "CapacitorUpdater.statsUrl";
|
|
70
70
|
private static final String CHANNEL_URL_PREF_KEY = "CapacitorUpdater.channelUrl";
|
|
71
|
+
private static final String DEFAULT_CHANNEL_PREF_KEY = "CapacitorUpdater.defaultChannel";
|
|
71
72
|
private static final String[] BREAKING_EVENT_NAMES = { "breakingAvailable", "majorAvailable" };
|
|
72
73
|
private static final String LAST_FAILED_BUNDLE_PREF_KEY = "CapacitorUpdater.lastFailedBundle";
|
|
73
74
|
|
|
74
|
-
private final String pluginVersion = "
|
|
75
|
+
private final String pluginVersion = "8.0.0";
|
|
75
76
|
private static final String DELAY_CONDITION_PREFERENCES = "";
|
|
76
77
|
|
|
77
78
|
private SharedPreferences.Editor editor;
|
|
@@ -100,6 +101,7 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
100
101
|
private Boolean onLaunchDirectUpdateUsed = false;
|
|
101
102
|
Boolean shakeMenuEnabled = false;
|
|
102
103
|
private Boolean allowManualBundleError = false;
|
|
104
|
+
private Boolean allowSetDefaultChannel = true;
|
|
103
105
|
|
|
104
106
|
private Boolean isPreviousMainActivity = true;
|
|
105
107
|
|
|
@@ -301,6 +303,7 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
301
303
|
|
|
302
304
|
this.persistCustomId = this.getConfig().getBoolean("persistCustomId", false);
|
|
303
305
|
this.persistModifyUrl = this.getConfig().getBoolean("persistModifyUrl", false);
|
|
306
|
+
this.allowSetDefaultChannel = this.getConfig().getBoolean("allowSetDefaultChannel", true);
|
|
304
307
|
this.implementation.publicKey = this.getConfig().getString("publicKey", "");
|
|
305
308
|
this.implementation.statsUrl = this.getConfig().getString("statsUrl", statsUrlDefault);
|
|
306
309
|
this.implementation.channelUrl = this.getConfig().getString("channelUrl", channelUrlDefault);
|
|
@@ -320,8 +323,21 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
320
323
|
}
|
|
321
324
|
}
|
|
322
325
|
}
|
|
326
|
+
|
|
327
|
+
// Load defaultChannel: first try from persistent storage (set via setChannel), then fall back to config
|
|
328
|
+
if (this.prefs.contains(DEFAULT_CHANNEL_PREF_KEY)) {
|
|
329
|
+
final String storedDefaultChannel = this.prefs.getString(DEFAULT_CHANNEL_PREF_KEY, "");
|
|
330
|
+
if (storedDefaultChannel != null && !storedDefaultChannel.isEmpty()) {
|
|
331
|
+
this.implementation.defaultChannel = storedDefaultChannel;
|
|
332
|
+
logger.info("Loaded persisted defaultChannel from setChannel()");
|
|
333
|
+
} else {
|
|
334
|
+
this.implementation.defaultChannel = this.getConfig().getString("defaultChannel", "");
|
|
335
|
+
}
|
|
336
|
+
} else {
|
|
337
|
+
this.implementation.defaultChannel = this.getConfig().getString("defaultChannel", "");
|
|
338
|
+
}
|
|
339
|
+
|
|
323
340
|
int userValue = this.getConfig().getInt("periodCheckDelay", 0);
|
|
324
|
-
this.implementation.defaultChannel = this.getConfig().getString("defaultChannel", "");
|
|
325
341
|
|
|
326
342
|
if (userValue >= 0 && userValue <= 600) {
|
|
327
343
|
this.periodCheckDelay = 600 * 1000;
|
|
@@ -863,27 +879,33 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
863
879
|
|
|
864
880
|
try {
|
|
865
881
|
logger.info("unsetChannel triggerAutoUpdate: " + triggerAutoUpdate);
|
|
866
|
-
startNewThread(() ->
|
|
867
|
-
CapacitorUpdaterPlugin.this.
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
JSObject
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
+
startNewThread(() -> {
|
|
883
|
+
String configDefaultChannel = CapacitorUpdaterPlugin.this.getConfig().getString("defaultChannel", "");
|
|
884
|
+
CapacitorUpdaterPlugin.this.implementation.unsetChannel(
|
|
885
|
+
CapacitorUpdaterPlugin.this.editor,
|
|
886
|
+
DEFAULT_CHANNEL_PREF_KEY,
|
|
887
|
+
configDefaultChannel,
|
|
888
|
+
(res) -> {
|
|
889
|
+
JSObject jsRes = mapToJSObject(res);
|
|
890
|
+
if (jsRes.has("error")) {
|
|
891
|
+
String errorMessage = jsRes.has("message") ? jsRes.getString("message") : jsRes.getString("error");
|
|
892
|
+
String errorCode = jsRes.getString("error");
|
|
893
|
+
|
|
894
|
+
JSObject errorObj = new JSObject();
|
|
895
|
+
errorObj.put("message", errorMessage);
|
|
896
|
+
errorObj.put("error", errorCode);
|
|
897
|
+
|
|
898
|
+
call.reject(errorMessage, "UNSETCHANNEL_FAILED", null, errorObj);
|
|
899
|
+
} else {
|
|
900
|
+
if (CapacitorUpdaterPlugin.this._isAutoUpdateEnabled() && Boolean.TRUE.equals(triggerAutoUpdate)) {
|
|
901
|
+
logger.info("Calling autoupdater after channel change!");
|
|
902
|
+
backgroundDownload();
|
|
903
|
+
}
|
|
904
|
+
call.resolve(jsRes);
|
|
882
905
|
}
|
|
883
|
-
call.resolve(jsRes);
|
|
884
906
|
}
|
|
885
|
-
|
|
886
|
-
);
|
|
907
|
+
);
|
|
908
|
+
});
|
|
887
909
|
} catch (final Exception e) {
|
|
888
910
|
logger.error("Failed to unsetChannel: " + e.getMessage());
|
|
889
911
|
call.reject("Failed to unsetChannel: ", e);
|
|
@@ -906,25 +928,42 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
906
928
|
try {
|
|
907
929
|
logger.info("setChannel " + channel + " triggerAutoUpdate: " + triggerAutoUpdate);
|
|
908
930
|
startNewThread(() ->
|
|
909
|
-
CapacitorUpdaterPlugin.this.implementation.setChannel(
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
931
|
+
CapacitorUpdaterPlugin.this.implementation.setChannel(
|
|
932
|
+
channel,
|
|
933
|
+
CapacitorUpdaterPlugin.this.editor,
|
|
934
|
+
DEFAULT_CHANNEL_PREF_KEY,
|
|
935
|
+
CapacitorUpdaterPlugin.this.allowSetDefaultChannel,
|
|
936
|
+
(res) -> {
|
|
937
|
+
JSObject jsRes = mapToJSObject(res);
|
|
938
|
+
if (jsRes.has("error")) {
|
|
939
|
+
String errorMessage = jsRes.has("message") ? jsRes.getString("message") : jsRes.getString("error");
|
|
940
|
+
String errorCode = jsRes.getString("error");
|
|
941
|
+
|
|
942
|
+
// Fire channelPrivate event if channel doesn't allow self-assignment
|
|
943
|
+
if (
|
|
944
|
+
errorCode.contains("cannot_update_via_private_channel") ||
|
|
945
|
+
errorCode.contains("channel_self_set_not_allowed")
|
|
946
|
+
) {
|
|
947
|
+
JSObject eventData = new JSObject();
|
|
948
|
+
eventData.put("channel", channel);
|
|
949
|
+
eventData.put("message", errorMessage);
|
|
950
|
+
notifyListeners("channelPrivate", eventData);
|
|
951
|
+
}
|
|
914
952
|
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
953
|
+
JSObject errorObj = new JSObject();
|
|
954
|
+
errorObj.put("message", errorMessage);
|
|
955
|
+
errorObj.put("error", errorCode);
|
|
918
956
|
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
957
|
+
call.reject(errorMessage, "SETCHANNEL_FAILED", null, errorObj);
|
|
958
|
+
} else {
|
|
959
|
+
if (CapacitorUpdaterPlugin.this._isAutoUpdateEnabled() && Boolean.TRUE.equals(triggerAutoUpdate)) {
|
|
960
|
+
logger.info("Calling autoupdater after channel change!");
|
|
961
|
+
backgroundDownload();
|
|
962
|
+
}
|
|
963
|
+
call.resolve(jsRes);
|
|
924
964
|
}
|
|
925
|
-
call.resolve(jsRes);
|
|
926
965
|
}
|
|
927
|
-
|
|
966
|
+
)
|
|
928
967
|
);
|
|
929
968
|
} catch (final Exception e) {
|
|
930
969
|
logger.error("Failed to setChannel: " + channel + " " + e.getMessage());
|