@capgo/capacitor-updater 5.31.0 → 5.35.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -66,6 +66,14 @@ The most complete [documentation here](https://capgo.app/docs/).
66
66
  ## Community
67
67
  Join the [discord](https://discord.gg/VnYRvBfgA6) to get help.
68
68
 
69
+ ## Migration to v7.34
70
+
71
+ - **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.
72
+ - Channel assignments persist between app restarts
73
+ - Use `unsetChannel()` to clear the local assignment and revert to `defaultChannel`
74
+ - Old devices (< v7.34.0) will continue using cloud-based storage
75
+ - **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.
76
+
69
77
  ## Migration to v7
70
78
 
71
79
  - `privateKey` is not available anymore, it was used for the old encryption method. to migrate follow this guide : [https://capgo.app/docs/plugin/cloud-mode/getting-started/](https://capgo.app/docs/cli/migrations/encryption/)
@@ -271,6 +279,7 @@ CapacitorUpdater can be configured with these options:
271
279
  | **`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 |
272
280
  | **`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 |
273
281
  | **`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 |
282
+ | **`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 |
274
283
  | **`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 |
275
284
  | **`appId`** | <code>string</code> | Configure the app id for the app in the config. | <code>undefined</code> | 6.0.0 |
276
285
  | **`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 |
@@ -313,6 +322,7 @@ In `capacitor.config.json`:
313
322
  "allowManualBundleError": undefined,
314
323
  "persistCustomId": undefined,
315
324
  "persistModifyUrl": undefined,
325
+ "allowSetDefaultChannel": undefined,
316
326
  "defaultChannel": undefined,
317
327
  "appId": undefined,
318
328
  "keepUrlPathAfterReload": undefined,
@@ -361,6 +371,7 @@ const config: CapacitorConfig = {
361
371
  allowManualBundleError: undefined,
362
372
  persistCustomId: undefined,
363
373
  persistModifyUrl: undefined,
374
+ allowSetDefaultChannel: undefined,
364
375
  defaultChannel: undefined,
365
376
  appId: undefined,
366
377
  keepUrlPathAfterReload: undefined,
@@ -416,6 +427,7 @@ export default config;
416
427
  * [`addListener('downloadFailed', ...)`](#addlistenerdownloadfailed-)
417
428
  * [`addListener('appReloaded', ...)`](#addlistenerappreloaded-)
418
429
  * [`addListener('appReady', ...)`](#addlistenerappready-)
430
+ * [`addListener('channelPrivate', ...)`](#addlistenerchannelprivate-)
419
431
  * [`isAutoUpdateAvailable()`](#isautoupdateavailable)
420
432
  * [`getNextBundle()`](#getnextbundle)
421
433
  * [`getFailedUpdate()`](#getfailedupdate)
@@ -863,6 +875,34 @@ After receiving the latest version info, you can:
863
875
  2. Download it using {@link download}
864
876
  3. Apply it using {@link next} or {@link set}
865
877
 
878
+ **Important: Error handling for "no new version available"**
879
+
880
+ When the device's current version matches the latest version on the server (i.e., the device is already
881
+ up-to-date), the server returns a 200 response with `error: "no_new_version_available"` and
882
+ `message: "No new version available"`. **This causes `getLatest()` to throw an error**, even though
883
+ this is a normal, expected condition.
884
+
885
+ You should catch this specific error to handle it gracefully:
886
+
887
+ ```typescript
888
+ try {
889
+ const latest = await CapacitorUpdater.getLatest();
890
+ // New version is available, proceed with download
891
+ } catch (error) {
892
+ if (error.message === 'No new version available') {
893
+ // Device is already on the latest version - this is normal
894
+ console.log('Already up to date');
895
+ } else {
896
+ // Actual error occurred
897
+ console.error('Failed to check for updates:', error);
898
+ }
899
+ }
900
+ ```
901
+
902
+ In this scenario, the server:
903
+ - Logs the request with a "No new version available" message
904
+ - Sends a "noNew" stat action to track that the device checked for updates but was already current (done on the backend)
905
+
866
906
  | Param | Type | Description |
867
907
  | ------------- | ------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
868
908
  | **`options`** | <code><a href="#getlatestoptions">GetLatestOptions</a></code> | Optional {@link <a href="#getlatestoptions">GetLatestOptions</a>} to specify which channel to check. |
@@ -898,6 +938,19 @@ Channels allow you to distribute different bundle versions to different groups o
898
938
  - At app boot/initialization - use {@link PluginsConfig.CapacitorUpdater.defaultChannel} config instead
899
939
  - Before user interaction
900
940
 
941
+ **Important: Listen for the `channelPrivate` event**
942
+
943
+ When a user attempts to set a channel that doesn't allow device self-assignment, the method will
944
+ throw an error AND fire a {@link addListener}('channelPrivate') event. You should listen to this event
945
+ to provide appropriate feedback to users:
946
+
947
+ ```typescript
948
+ CapacitorUpdater.addListener('channelPrivate', (data) =&gt; {
949
+ console.warn(`Cannot access channel "${data.channel}": ${data.message}`);
950
+ // Show user-friendly message
951
+ });
952
+ ```
953
+
901
954
  This sends a request to the Capgo backend linking your device ID to the specified channel.
902
955
 
903
956
  | Param | Type | Description |
@@ -1362,6 +1415,31 @@ Listen for app ready event in the App, let you know when app is ready to use, th
1362
1415
  --------------------
1363
1416
 
1364
1417
 
1418
+ #### addListener('channelPrivate', ...)
1419
+
1420
+ ```typescript
1421
+ addListener(eventName: 'channelPrivate', listenerFunc: (state: ChannelPrivateEvent) => void) => Promise<PluginListenerHandle>
1422
+ ```
1423
+
1424
+ Listen for channel private event, fired when attempting to set a channel that doesn't allow device self-assignment.
1425
+
1426
+ This event is useful for:
1427
+ - Informing users they don't have permission to switch to a specific channel
1428
+ - Implementing custom error handling for channel restrictions
1429
+ - Logging unauthorized channel access attempts
1430
+
1431
+ | Param | Type |
1432
+ | ------------------ | --------------------------------------------------------------------------------------- |
1433
+ | **`eventName`** | <code>'channelPrivate'</code> |
1434
+ | **`listenerFunc`** | <code>(state: <a href="#channelprivateevent">ChannelPrivateEvent</a>) =&gt; void</code> |
1435
+
1436
+ **Returns:** <code>Promise&lt;<a href="#pluginlistenerhandle">PluginListenerHandle</a>&gt;</code>
1437
+
1438
+ **Since:** 7.34.0
1439
+
1440
+ --------------------
1441
+
1442
+
1365
1443
  #### isAutoUpdateAvailable()
1366
1444
 
1367
1445
  ```typescript
@@ -1678,18 +1756,20 @@ If you don't use backend, you need to provide the URL and version of the bundle.
1678
1756
 
1679
1757
  ##### LatestVersion
1680
1758
 
1681
- | Prop | Type | Description | Since |
1682
- | ---------------- | ---------------------------- | -------------------------------------------------------------------- | ------ |
1683
- | **`version`** | <code>string</code> | Result of getLatest method | 4.0.0 |
1684
- | **`checksum`** | <code>string</code> | | 6 |
1685
- | **`breaking`** | <code>boolean</code> | Indicates whether the update was flagged as breaking by the backend. | 7.22.0 |
1686
- | **`major`** | <code>boolean</code> | | |
1687
- | **`message`** | <code>string</code> | | |
1688
- | **`sessionKey`** | <code>string</code> | | |
1689
- | **`error`** | <code>string</code> | | |
1690
- | **`old`** | <code>string</code> | | |
1691
- | **`url`** | <code>string</code> | | |
1692
- | **`manifest`** | <code>ManifestEntry[]</code> | | 6.1 |
1759
+ | Prop | Type | Description | Since |
1760
+ | ---------------- | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------ |
1761
+ | **`version`** | <code>string</code> | Result of getLatest method | 4.0.0 |
1762
+ | **`checksum`** | <code>string</code> | | 6 |
1763
+ | **`breaking`** | <code>boolean</code> | Indicates whether the update was flagged as breaking by the backend. | 7.22.0 |
1764
+ | **`major`** | <code>boolean</code> | | |
1765
+ | **`message`** | <code>string</code> | Optional message from the server. When no new version is available, this will be "No new version available". | |
1766
+ | **`sessionKey`** | <code>string</code> | | |
1767
+ | **`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 | |
1768
+ | **`old`** | <code>string</code> | The previous/current version name (provided for reference). | |
1769
+ | **`url`** | <code>string</code> | Download URL for the bundle (when a new version is available). | |
1770
+ | **`manifest`** | <code>ManifestEntry[]</code> | File list for partial updates (when using multi-file downloads). | 6.1 |
1771
+ | **`link`** | <code>string</code> | Optional link associated with this bundle version (e.g., release notes URL, changelog, GitHub release). | 7.35.0 |
1772
+ | **`comment`** | <code>string</code> | Optional comment or description for this bundle version. | 7.35.0 |
1693
1773
 
1694
1774
 
1695
1775
  ##### GetLatestOptions
@@ -1851,6 +1931,14 @@ If you don't use backend, you need to provide the URL and version of the bundle.
1851
1931
  | **`status`** | <code>string</code> | | |
1852
1932
 
1853
1933
 
1934
+ ##### ChannelPrivateEvent
1935
+
1936
+ | Prop | Type | Description | Since |
1937
+ | ------------- | ------------------- | ----------------------------------------------------------------------------------- | ------ |
1938
+ | **`channel`** | <code>string</code> | Emitted when attempting to set a channel that doesn't allow device self-assignment. | 7.34.0 |
1939
+ | **`message`** | <code>string</code> | | |
1940
+
1941
+
1854
1942
  ##### AutoUpdateAvailable
1855
1943
 
1856
1944
  | Prop | Type |
@@ -49,16 +49,16 @@ repositories {
49
49
 
50
50
 
51
51
  dependencies {
52
- def work_version = "2.11.0"
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.4.8-android"
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.14.2'
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 = "5.31.0";
75
+ private final String pluginVersion = "5.35.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.implementation.unsetChannel((res) -> {
868
- JSObject jsRes = mapToJSObject(res);
869
- if (jsRes.has("error")) {
870
- String errorMessage = jsRes.has("message") ? jsRes.getString("message") : jsRes.getString("error");
871
- String errorCode = jsRes.getString("error");
872
-
873
- JSObject errorObj = new JSObject();
874
- errorObj.put("message", errorMessage);
875
- errorObj.put("error", errorCode);
876
-
877
- call.reject(errorMessage, "UNSETCHANNEL_FAILED", null, errorObj);
878
- } else {
879
- if (CapacitorUpdaterPlugin.this._isAutoUpdateEnabled() && Boolean.TRUE.equals(triggerAutoUpdate)) {
880
- logger.info("Calling autoupdater after channel change!");
881
- backgroundDownload();
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(channel, (res) -> {
910
- JSObject jsRes = mapToJSObject(res);
911
- if (jsRes.has("error")) {
912
- String errorMessage = jsRes.has("message") ? jsRes.getString("message") : jsRes.getString("error");
913
- String errorCode = jsRes.getString("error");
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
- JSObject errorObj = new JSObject();
916
- errorObj.put("message", errorMessage);
917
- errorObj.put("error", errorCode);
953
+ JSObject errorObj = new JSObject();
954
+ errorObj.put("message", errorMessage);
955
+ errorObj.put("error", errorCode);
918
956
 
919
- call.reject(errorMessage, "SETCHANNEL_FAILED", null, errorObj);
920
- } else {
921
- if (CapacitorUpdaterPlugin.this._isAutoUpdateEnabled() && Boolean.TRUE.equals(triggerAutoUpdate)) {
922
- logger.info("Calling autoupdater after channel change!");
923
- backgroundDownload();
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());