@capgo/capacitor-updater 8.45.9 → 8.45.11
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 +74 -28
- package/android/build.gradle +1 -1
- package/android/src/main/java/ee/forgr/capacitor_updater/CapacitorUpdaterPlugin.java +185 -86
- package/android/src/main/java/ee/forgr/capacitor_updater/CapgoUpdater.java +40 -16
- package/android/src/main/java/ee/forgr/capacitor_updater/ShakeMenu.java +27 -3
- package/dist/docs.json +163 -4
- package/dist/esm/definitions.d.ts +82 -19
- package/dist/esm/definitions.js.map +1 -1
- package/ios/Sources/CapacitorUpdaterPlugin/BundleInfo.swift +2 -2
- package/ios/Sources/CapacitorUpdaterPlugin/BundleStatus.swift +78 -2
- package/ios/Sources/CapacitorUpdaterPlugin/CapacitorUpdaterPlugin.swift +289 -94
- package/ios/Sources/CapacitorUpdaterPlugin/CapgoUpdater.swift +672 -300
- package/ios/Sources/CapacitorUpdaterPlugin/InternalUtils.swift +31 -0
- package/ios/Sources/CapacitorUpdaterPlugin/ShakeMenu.swift +20 -3
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -462,6 +462,7 @@ export default config;
|
|
|
462
462
|
* [`removeAllListeners()`](#removealllisteners)
|
|
463
463
|
* [`addListener('download', ...)`](#addlistenerdownload-)
|
|
464
464
|
* [`addListener('noNeedUpdate', ...)`](#addlistenernoneedupdate-)
|
|
465
|
+
* [`addListener('updateCheckResult', ...)`](#addlistenerupdatecheckresult-)
|
|
465
466
|
* [`addListener('updateAvailable', ...)`](#addlistenerupdateavailable-)
|
|
466
467
|
* [`addListener('downloadComplete', ...)`](#addlistenerdownloadcomplete-)
|
|
467
468
|
* [`addListener('breakingAvailable', ...)`](#addlistenerbreakingavailable-)
|
|
@@ -929,27 +930,23 @@ After receiving the latest version info, you can:
|
|
|
929
930
|
2. Download it using {@link download}
|
|
930
931
|
3. Apply it using {@link next} or {@link set}
|
|
931
932
|
|
|
932
|
-
**Important:
|
|
933
|
+
**Important: Handling "no new version available"**
|
|
933
934
|
|
|
934
935
|
When the device's current version matches the latest version on the server (i.e., the device is already
|
|
935
936
|
up-to-date), the server returns a 200 response with `error: "no_new_version_available"` and
|
|
936
|
-
`message: "No new version available"`.
|
|
937
|
-
|
|
937
|
+
`message: "No new version available"`. This is a normal, expected condition and resolves with
|
|
938
|
+
`kind: "up_to_date"` when the backend provides that classification.
|
|
938
939
|
|
|
939
|
-
You should
|
|
940
|
+
You should check `kind` and `error` before attempting to download:
|
|
940
941
|
|
|
941
942
|
```typescript
|
|
942
|
-
|
|
943
|
-
|
|
943
|
+
const latest = await CapacitorUpdater.getLatest();
|
|
944
|
+
if (latest.kind === 'up_to_date') {
|
|
945
|
+
console.log('Already up to date');
|
|
946
|
+
} else if (latest.kind === 'blocked') {
|
|
947
|
+
console.log('Update is blocked:', latest.error);
|
|
948
|
+
} else if (latest.url) {
|
|
944
949
|
// New version is available, proceed with download
|
|
945
|
-
} catch (error) {
|
|
946
|
-
if (error.message === 'No new version available') {
|
|
947
|
-
// Device is already on the latest version - this is normal
|
|
948
|
-
console.log('Already up to date');
|
|
949
|
-
} else {
|
|
950
|
-
// Actual error occurred
|
|
951
|
-
console.error('Failed to check for updates:', error);
|
|
952
|
-
}
|
|
953
950
|
}
|
|
954
951
|
```
|
|
955
952
|
|
|
@@ -1251,6 +1248,7 @@ Remove all event listeners registered for this plugin.
|
|
|
1251
1248
|
This unregisters all listeners added via {@link addListener} for all event types:
|
|
1252
1249
|
- `download`
|
|
1253
1250
|
- `noNeedUpdate`
|
|
1251
|
+
- `updateCheckResult`
|
|
1254
1252
|
- `updateAvailable`
|
|
1255
1253
|
- `downloadComplete`
|
|
1256
1254
|
- `downloadFailed`
|
|
@@ -1308,6 +1306,31 @@ Listen for no need to update event, useful when you want force check every time
|
|
|
1308
1306
|
--------------------
|
|
1309
1307
|
|
|
1310
1308
|
|
|
1309
|
+
#### addListener('updateCheckResult', ...)
|
|
1310
|
+
|
|
1311
|
+
```typescript
|
|
1312
|
+
addListener(eventName: 'updateCheckResult', listenerFunc: (state: UpdateCheckResultEvent) => void) => Promise<PluginListenerHandle>
|
|
1313
|
+
```
|
|
1314
|
+
|
|
1315
|
+
Listen for update check results before the updater decides whether to download.
|
|
1316
|
+
The backend can classify the <a href="#updatecheckresultevent">UpdateCheckResultEvent</a> payload as `up_to_date`, `blocked`, or `failed`.
|
|
1317
|
+
|
|
1318
|
+
This event is emitted alongside legacy events. For `up_to_date` and `blocked`, it is emitted before
|
|
1319
|
+
`noNeedUpdate` and does not emit `downloadFailed`. For `failed`, it is emitted before the legacy
|
|
1320
|
+
`downloadFailed` event and keeps the existing failure stats behavior.
|
|
1321
|
+
|
|
1322
|
+
| Param | Type |
|
|
1323
|
+
| ------------------ | --------------------------------------------------------------------------------------------- |
|
|
1324
|
+
| **`eventName`** | <code>'updateCheckResult'</code> |
|
|
1325
|
+
| **`listenerFunc`** | <code>(state: <a href="#updatecheckresultevent">UpdateCheckResultEvent</a>) => void</code> |
|
|
1326
|
+
|
|
1327
|
+
**Returns:** <code>Promise<<a href="#pluginlistenerhandle">PluginListenerHandle</a>></code>
|
|
1328
|
+
|
|
1329
|
+
**Since:** 8.45.11
|
|
1330
|
+
|
|
1331
|
+
--------------------
|
|
1332
|
+
|
|
1333
|
+
|
|
1311
1334
|
#### addListener('updateAvailable', ...)
|
|
1312
1335
|
|
|
1313
1336
|
```typescript
|
|
@@ -2094,20 +2117,22 @@ If you don't use backend, you need to provide the URL and version of the bundle.
|
|
|
2094
2117
|
|
|
2095
2118
|
##### LatestVersion
|
|
2096
2119
|
|
|
2097
|
-
| Prop | Type
|
|
2098
|
-
| ---------------- |
|
|
2099
|
-
| **`version`** | <code>string</code>
|
|
2100
|
-
| **`checksum`** | <code>string</code>
|
|
2101
|
-
| **`breaking`** | <code>boolean</code>
|
|
2102
|
-
| **`major`** | <code>boolean</code>
|
|
2103
|
-
| **`message`** | <code>string</code>
|
|
2104
|
-
| **`sessionKey`** | <code>string</code>
|
|
2105
|
-
| **`error`** | <code>string</code>
|
|
2106
|
-
| **`
|
|
2107
|
-
| **`
|
|
2108
|
-
| **`
|
|
2109
|
-
| **`
|
|
2110
|
-
| **`
|
|
2120
|
+
| Prop | Type | Description | Since |
|
|
2121
|
+
| ---------------- | ----------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ | ------- |
|
|
2122
|
+
| **`version`** | <code>string</code> | Result of getLatest method | 4.0.0 |
|
|
2123
|
+
| **`checksum`** | <code>string</code> | | 6 |
|
|
2124
|
+
| **`breaking`** | <code>boolean</code> | Indicates whether the update was flagged as breaking by the backend. | 7.22.0 |
|
|
2125
|
+
| **`major`** | <code>boolean</code> | | |
|
|
2126
|
+
| **`message`** | <code>string</code> | Optional message from the server. When no new version is available, this will be "No new version available". | |
|
|
2127
|
+
| **`sessionKey`** | <code>string</code> | | |
|
|
2128
|
+
| **`error`** | <code>string</code> | Error code from the server, if any. Use `kind` for classification instead of parsing this value. | |
|
|
2129
|
+
| **`kind`** | <code><a href="#updateresponsekind">UpdateResponseKind</a></code> | Classification for this response, provided by the backend. | 8.45.11 |
|
|
2130
|
+
| **`statusCode`** | <code>number</code> | HTTP status code returned by the update server for classified update-check responses. | 8.45.11 |
|
|
2131
|
+
| **`old`** | <code>string</code> | The previous/current version name (provided for reference). | |
|
|
2132
|
+
| **`url`** | <code>string</code> | Download URL for the bundle (when a new version is available). | |
|
|
2133
|
+
| **`manifest`** | <code>ManifestEntry[]</code> | File list for delta updates (when using multi-file downloads). | 6.1 |
|
|
2134
|
+
| **`link`** | <code>string</code> | Optional link associated with this bundle version (e.g., release notes URL, changelog, GitHub release). | 7.35.0 |
|
|
2135
|
+
| **`comment`** | <code>string</code> | Optional comment or description for this bundle version. | 7.35.0 |
|
|
2111
2136
|
|
|
2112
2137
|
|
|
2113
2138
|
##### GetLatestOptions
|
|
@@ -2226,6 +2251,18 @@ If you don't use backend, you need to provide the URL and version of the bundle.
|
|
|
2226
2251
|
| **`bundle`** | <code><a href="#bundleinfo">BundleInfo</a></code> | Current status of download, between 0 and 100. | 4.0.0 |
|
|
2227
2252
|
|
|
2228
2253
|
|
|
2254
|
+
##### UpdateCheckResultEvent
|
|
2255
|
+
|
|
2256
|
+
| Prop | Type | Description | Since |
|
|
2257
|
+
| ---------------- | ----------------------------------------------------------------- | -------------------------------------------------------------------- | ------- |
|
|
2258
|
+
| **`kind`** | <code><a href="#updateresponsekind">UpdateResponseKind</a></code> | Classification for the update check result, provided by the backend. | 8.45.11 |
|
|
2259
|
+
| **`error`** | <code>string</code> | Backend error code, when provided. | 8.45.11 |
|
|
2260
|
+
| **`message`** | <code>string</code> | Backend message, when provided. | 8.45.11 |
|
|
2261
|
+
| **`statusCode`** | <code>number</code> | HTTP status code returned by the update endpoint. | 8.45.11 |
|
|
2262
|
+
| **`version`** | <code>string</code> | Version referenced by the update check result. | 8.45.11 |
|
|
2263
|
+
| **`bundle`** | <code><a href="#bundleinfo">BundleInfo</a></code> | Current bundle on the device. | 8.45.11 |
|
|
2264
|
+
|
|
2265
|
+
|
|
2229
2266
|
##### UpdateAvailableEvent
|
|
2230
2267
|
|
|
2231
2268
|
| Prop | Type | Description | Since |
|
|
@@ -2417,6 +2454,15 @@ error: The bundle has failed to download.
|
|
|
2417
2454
|
<code>'background' | 'kill' | 'nativeVersion' | 'date'</code>
|
|
2418
2455
|
|
|
2419
2456
|
|
|
2457
|
+
##### UpdateResponseKind
|
|
2458
|
+
|
|
2459
|
+
Classification for update-check responses that do not provide a downloadable bundle.
|
|
2460
|
+
The update backend provides this field directly. Missing or unknown values are treated as
|
|
2461
|
+
failed by native clients.
|
|
2462
|
+
|
|
2463
|
+
<code>'up_to_date' | 'blocked' | 'failed'</code>
|
|
2464
|
+
|
|
2465
|
+
|
|
2420
2466
|
##### BreakingAvailableEvent
|
|
2421
2467
|
|
|
2422
2468
|
Payload emitted by {@link CapacitorUpdaterPlugin.addListener} with `breakingAvailable`.
|
package/android/build.gradle
CHANGED
|
@@ -54,7 +54,7 @@ dependencies {
|
|
|
54
54
|
implementation "androidx.work:work-runtime:$work_version"
|
|
55
55
|
implementation "androidx.lifecycle:lifecycle-process:$lifecycle_version"
|
|
56
56
|
implementation "com.google.android.gms:play-services-tasks:18.4.1"
|
|
57
|
-
implementation "com.google.guava:guava:33.
|
|
57
|
+
implementation "com.google.guava:guava:33.6.0-android"
|
|
58
58
|
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
|
59
59
|
implementation project(':capacitor-android')
|
|
60
60
|
implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion"
|
|
@@ -50,7 +50,6 @@ import java.io.IOException;
|
|
|
50
50
|
import java.net.MalformedURLException;
|
|
51
51
|
import java.net.URL;
|
|
52
52
|
import java.util.ArrayList;
|
|
53
|
-
import java.util.Arrays;
|
|
54
53
|
import java.util.Date;
|
|
55
54
|
import java.util.HashSet;
|
|
56
55
|
import java.util.List;
|
|
@@ -90,7 +89,7 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
90
89
|
private static final int SPLASH_SCREEN_MAX_RETRIES = 20;
|
|
91
90
|
private static final long PENDING_BUNDLE_APP_READY_MIN_TIMEOUT_MS = 30000L;
|
|
92
91
|
|
|
93
|
-
private final String pluginVersion = "8.45.
|
|
92
|
+
private final String pluginVersion = "8.45.11";
|
|
94
93
|
private static final String DELAY_CONDITION_PREFERENCES = "";
|
|
95
94
|
|
|
96
95
|
private SharedPreferences.Editor editor;
|
|
@@ -1293,6 +1292,23 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
1293
1292
|
startNewThread(() ->
|
|
1294
1293
|
CapacitorUpdaterPlugin.this.implementation.listChannels((res) -> {
|
|
1295
1294
|
JSObject jsRes = InternalUtils.mapToJSObject(res);
|
|
1295
|
+
Object channels = res.get("channels");
|
|
1296
|
+
if (channels instanceof List<?> channelsList) {
|
|
1297
|
+
JSArray channelsArray = new JSArray();
|
|
1298
|
+
for (Object channel : channelsList) {
|
|
1299
|
+
if (channel instanceof Map<?, ?> channelMap) {
|
|
1300
|
+
JSObject channelObject = new JSObject();
|
|
1301
|
+
for (Map.Entry<?, ?> entry : channelMap.entrySet()) {
|
|
1302
|
+
Object key = entry.getKey();
|
|
1303
|
+
if (key != null) {
|
|
1304
|
+
channelObject.put(key.toString(), entry.getValue());
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1307
|
+
channelsArray.put(channelObject);
|
|
1308
|
+
}
|
|
1309
|
+
}
|
|
1310
|
+
jsRes.put("channels", channelsArray);
|
|
1311
|
+
}
|
|
1296
1312
|
if (jsRes.has("error")) {
|
|
1297
1313
|
String errorMessage = jsRes.has("message") ? jsRes.getString("message") : jsRes.getString("error");
|
|
1298
1314
|
String errorCode = jsRes.getString("error");
|
|
@@ -1505,49 +1521,51 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
1505
1521
|
|
|
1506
1522
|
@PluginMethod
|
|
1507
1523
|
public void reload(final PluginCall call) {
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
this.implementation.prepareResetStateForTransition();
|
|
1519
|
-
didApplyPendingBundle = true;
|
|
1520
|
-
} else {
|
|
1521
|
-
didApplyPendingBundle = this.implementation.stagePendingReload(next);
|
|
1522
|
-
}
|
|
1523
|
-
if (didApplyPendingBundle && this._reload()) {
|
|
1524
|
+
startNewThread(() -> {
|
|
1525
|
+
try {
|
|
1526
|
+
final BundleInfo current = this.implementation.getCurrentBundle();
|
|
1527
|
+
final BundleInfo next = this.implementation.getNextBundle();
|
|
1528
|
+
|
|
1529
|
+
if (next != null && !next.isErrorStatus() && !next.getId().equals(current.getId())) {
|
|
1530
|
+
final CapgoUpdater.ResetState previousState = this.implementation.captureResetState();
|
|
1531
|
+
final String previousBundleName = this.implementation.getCurrentBundle().getVersionName();
|
|
1532
|
+
logger.info("Applying pending bundle before reload: " + next.getVersionName());
|
|
1533
|
+
final boolean didApplyPendingBundle;
|
|
1524
1534
|
if (next.isBuiltin()) {
|
|
1525
|
-
this.implementation.
|
|
1535
|
+
this.implementation.prepareResetStateForTransition();
|
|
1536
|
+
didApplyPendingBundle = true;
|
|
1526
1537
|
} else {
|
|
1527
|
-
this.implementation.
|
|
1538
|
+
didApplyPendingBundle = this.implementation.stagePendingReload(next);
|
|
1528
1539
|
}
|
|
1529
|
-
this.
|
|
1530
|
-
|
|
1531
|
-
|
|
1540
|
+
if (didApplyPendingBundle && this._reload()) {
|
|
1541
|
+
if (next.isBuiltin()) {
|
|
1542
|
+
this.implementation.finalizeResetTransition(previousBundleName, false);
|
|
1543
|
+
} else {
|
|
1544
|
+
this.implementation.finalizePendingReload(next, previousBundleName);
|
|
1545
|
+
}
|
|
1546
|
+
this.notifyBundleSet(next);
|
|
1547
|
+
this.implementation.setNextBundle(null);
|
|
1548
|
+
call.resolve();
|
|
1549
|
+
return;
|
|
1550
|
+
}
|
|
1551
|
+
this.implementation.restoreResetState(previousState);
|
|
1552
|
+
this.restoreLiveBundleStateAfterFailedReload();
|
|
1553
|
+
logger.error("Reload failed after applying pending bundle: " + next.getVersionName());
|
|
1554
|
+
call.reject("Reload failed after applying pending bundle: " + next.getVersionName());
|
|
1532
1555
|
return;
|
|
1533
1556
|
}
|
|
1534
|
-
this.implementation.restoreResetState(previousState);
|
|
1535
|
-
this.restoreLiveBundleStateAfterFailedReload();
|
|
1536
|
-
logger.error("Reload failed after applying pending bundle: " + next.getVersionName());
|
|
1537
|
-
call.reject("Reload failed after applying pending bundle: " + next.getVersionName());
|
|
1538
|
-
return;
|
|
1539
|
-
}
|
|
1540
1557
|
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1558
|
+
if (this._reload()) {
|
|
1559
|
+
call.resolve();
|
|
1560
|
+
} else {
|
|
1561
|
+
logger.error("Reload failed");
|
|
1562
|
+
call.reject("Reload failed");
|
|
1563
|
+
}
|
|
1564
|
+
} catch (final Exception e) {
|
|
1565
|
+
logger.error("Could not reload " + e.getMessage());
|
|
1566
|
+
call.reject("Could not reload", e);
|
|
1546
1567
|
}
|
|
1547
|
-
}
|
|
1548
|
-
logger.error("Could not reload " + e.getMessage());
|
|
1549
|
-
call.reject("Could not reload", e);
|
|
1550
|
-
}
|
|
1568
|
+
});
|
|
1551
1569
|
}
|
|
1552
1570
|
|
|
1553
1571
|
@PluginMethod
|
|
@@ -1580,23 +1598,25 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
1580
1598
|
call.reject("Set called without id");
|
|
1581
1599
|
return;
|
|
1582
1600
|
}
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1601
|
+
startNewThread(() -> {
|
|
1602
|
+
try {
|
|
1603
|
+
logger.info("Setting active bundle " + id);
|
|
1604
|
+
if (!this.implementation.set(id)) {
|
|
1605
|
+
logger.info("No such bundle " + id);
|
|
1606
|
+
call.reject("Update failed, id " + id + " does not exist.");
|
|
1607
|
+
} else if (!this._reload()) {
|
|
1608
|
+
logger.error("Reload failed after setting bundle " + id);
|
|
1609
|
+
call.reject("Reload failed after setting bundle " + id);
|
|
1610
|
+
} else {
|
|
1611
|
+
logger.info("Bundle successfully set to " + id);
|
|
1612
|
+
this.notifyBundleSet(this.implementation.getBundleInfo(id));
|
|
1613
|
+
call.resolve();
|
|
1614
|
+
}
|
|
1615
|
+
} catch (final Exception e) {
|
|
1616
|
+
logger.error("Could not set id " + id + " " + e.getMessage());
|
|
1617
|
+
call.reject("Could not set id " + id, e);
|
|
1595
1618
|
}
|
|
1596
|
-
}
|
|
1597
|
-
logger.error("Could not set id " + id + " " + e.getMessage());
|
|
1598
|
-
call.reject("Could not set id " + id, e);
|
|
1599
|
-
}
|
|
1619
|
+
});
|
|
1600
1620
|
}
|
|
1601
1621
|
|
|
1602
1622
|
@PluginMethod
|
|
@@ -1683,11 +1703,21 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
1683
1703
|
startNewThread(() ->
|
|
1684
1704
|
CapacitorUpdaterPlugin.this.implementation.getLatest(CapacitorUpdaterPlugin.this.updateUrl, channel, (res) -> {
|
|
1685
1705
|
JSObject jsRes = InternalUtils.mapToJSObject(res);
|
|
1686
|
-
if (jsRes.has("error")) {
|
|
1687
|
-
String error = jsRes.getString("error");
|
|
1706
|
+
if (jsRes.has("error") || jsRes.has("kind")) {
|
|
1707
|
+
String error = jsRes.has("error") ? jsRes.getString("error") : "";
|
|
1688
1708
|
String errorMessage = jsRes.has("message") ? jsRes.getString("message") : "server did not provide a message";
|
|
1689
|
-
|
|
1690
|
-
|
|
1709
|
+
String kind = CapacitorUpdaterPlugin.this.getUpdateResponseKind(jsRes.has("kind") ? jsRes.getString("kind") : null);
|
|
1710
|
+
jsRes.put("kind", kind);
|
|
1711
|
+
if ("failed".equals(kind)) {
|
|
1712
|
+
logger.error("getLatest failed with error: " + error + ", message: " + errorMessage);
|
|
1713
|
+
call.reject(error.isEmpty() ? errorMessage : error);
|
|
1714
|
+
} else {
|
|
1715
|
+
if (!jsRes.has("version") || jsRes.getString("version").isEmpty()) {
|
|
1716
|
+
jsRes.put("version", CapacitorUpdaterPlugin.this.implementation.getCurrentBundle().getVersionName());
|
|
1717
|
+
}
|
|
1718
|
+
logger.info("getLatest returned " + kind + ": " + errorMessage);
|
|
1719
|
+
call.resolve(jsRes);
|
|
1720
|
+
}
|
|
1691
1721
|
return;
|
|
1692
1722
|
} else if (jsRes.has("message")) {
|
|
1693
1723
|
call.reject(jsRes.getString("message"));
|
|
@@ -1772,19 +1802,21 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
1772
1802
|
|
|
1773
1803
|
@PluginMethod
|
|
1774
1804
|
public void reset(final PluginCall call) {
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1805
|
+
startNewThread(() -> {
|
|
1806
|
+
try {
|
|
1807
|
+
final Boolean toLastSuccessful = call.getBoolean("toLastSuccessful", false);
|
|
1808
|
+
final Boolean usePendingBundle = call.getBoolean("usePendingBundle", false);
|
|
1809
|
+
if (this._reset(toLastSuccessful, usePendingBundle)) {
|
|
1810
|
+
call.resolve();
|
|
1811
|
+
return;
|
|
1812
|
+
}
|
|
1813
|
+
logger.error("Reset failed");
|
|
1814
|
+
call.reject("Reset failed");
|
|
1815
|
+
} catch (final Exception e) {
|
|
1816
|
+
logger.error("Reset failed " + e.getMessage());
|
|
1817
|
+
call.reject("Reset failed", e);
|
|
1781
1818
|
}
|
|
1782
|
-
|
|
1783
|
-
call.reject("Reset failed");
|
|
1784
|
-
} catch (final Exception e) {
|
|
1785
|
-
logger.error("Reset failed " + e.getMessage());
|
|
1786
|
-
call.reject("Reset failed", e);
|
|
1787
|
-
}
|
|
1819
|
+
});
|
|
1788
1820
|
}
|
|
1789
1821
|
|
|
1790
1822
|
@PluginMethod
|
|
@@ -1850,12 +1882,33 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
1850
1882
|
try {
|
|
1851
1883
|
CapacitorUpdaterPlugin.this.implementation.getLatest(CapacitorUpdaterPlugin.this.updateUrl, null, (res) -> {
|
|
1852
1884
|
JSObject jsRes = InternalUtils.mapToJSObject(res);
|
|
1853
|
-
if (jsRes.has("error")) {
|
|
1854
|
-
|
|
1885
|
+
if (jsRes.has("error") || jsRes.has("kind")) {
|
|
1886
|
+
final BundleInfo current = CapacitorUpdaterPlugin.this.implementation.getCurrentBundle();
|
|
1887
|
+
String error = jsRes.has("error") ? jsRes.getString("error") : "";
|
|
1855
1888
|
String errorMessage = jsRes.has("message")
|
|
1856
1889
|
? jsRes.getString("message")
|
|
1857
1890
|
: "server did not provide a message";
|
|
1858
|
-
|
|
1891
|
+
int statusCode = jsRes.has("statusCode") ? jsRes.optInt("statusCode", 0) : 0;
|
|
1892
|
+
String kind = CapacitorUpdaterPlugin.this.getUpdateResponseKind(
|
|
1893
|
+
jsRes.has("kind") ? jsRes.getString("kind") : null
|
|
1894
|
+
);
|
|
1895
|
+
String latestVersion = jsRes.has("version") ? jsRes.getString("version") : current.getVersionName();
|
|
1896
|
+
CapacitorUpdaterPlugin.this.notifyUpdateCheckResult(
|
|
1897
|
+
kind,
|
|
1898
|
+
error,
|
|
1899
|
+
errorMessage,
|
|
1900
|
+
statusCode,
|
|
1901
|
+
latestVersion,
|
|
1902
|
+
current
|
|
1903
|
+
);
|
|
1904
|
+
|
|
1905
|
+
if ("failed".equals(kind)) {
|
|
1906
|
+
logger.error("getLatest failed with error: " + error + ", message: " + errorMessage);
|
|
1907
|
+
} else if ("blocked".equals(kind)) {
|
|
1908
|
+
logger.info("Update check blocked with error: " + error);
|
|
1909
|
+
} else {
|
|
1910
|
+
logger.info("No new version available");
|
|
1911
|
+
}
|
|
1859
1912
|
} else if (jsRes.has("version")) {
|
|
1860
1913
|
String newVersion = jsRes.getString("version");
|
|
1861
1914
|
String currentVersion = String.valueOf(CapacitorUpdaterPlugin.this.implementation.getCurrentBundle());
|
|
@@ -1980,10 +2033,22 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
1980
2033
|
this.checkAppReady(this.resolveAppReadyCheckTimeoutMs());
|
|
1981
2034
|
}
|
|
1982
2035
|
|
|
2036
|
+
synchronized boolean shouldInterruptAppReadyCheck(final Thread existingCheck, final Thread currentThread) {
|
|
2037
|
+
return existingCheck != null && existingCheck != currentThread;
|
|
2038
|
+
}
|
|
2039
|
+
|
|
2040
|
+
synchronized void clearAppReadyCheckIfCurrent(final Thread expectedThread) {
|
|
2041
|
+
if (this.appReadyCheck == expectedThread) {
|
|
2042
|
+
this.appReadyCheck = null;
|
|
2043
|
+
}
|
|
2044
|
+
}
|
|
2045
|
+
|
|
1983
2046
|
private void checkAppReady(final long waitTimeMs) {
|
|
1984
2047
|
try {
|
|
1985
|
-
|
|
1986
|
-
|
|
2048
|
+
final Thread currentThread = Thread.currentThread();
|
|
2049
|
+
final Thread existingCheck = this.appReadyCheck;
|
|
2050
|
+
if (this.shouldInterruptAppReadyCheck(existingCheck, currentThread)) {
|
|
2051
|
+
existingCheck.interrupt();
|
|
1987
2052
|
}
|
|
1988
2053
|
this.appReadyCheck = startNewThread(new DeferredNotifyAppReadyCheck(waitTimeMs));
|
|
1989
2054
|
} catch (final Exception e) {
|
|
@@ -2000,6 +2065,31 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
2000
2065
|
}
|
|
2001
2066
|
}
|
|
2002
2067
|
|
|
2068
|
+
private String getUpdateResponseKind(final String kind) {
|
|
2069
|
+
if ("up_to_date".equals(kind) || "blocked".equals(kind) || "failed".equals(kind)) {
|
|
2070
|
+
return kind;
|
|
2071
|
+
}
|
|
2072
|
+
return "failed";
|
|
2073
|
+
}
|
|
2074
|
+
|
|
2075
|
+
private void notifyUpdateCheckResult(
|
|
2076
|
+
final String kind,
|
|
2077
|
+
final String error,
|
|
2078
|
+
final String message,
|
|
2079
|
+
final int statusCode,
|
|
2080
|
+
final String version,
|
|
2081
|
+
final BundleInfo current
|
|
2082
|
+
) {
|
|
2083
|
+
JSObject ret = new JSObject();
|
|
2084
|
+
ret.put("kind", kind);
|
|
2085
|
+
ret.put("error", error);
|
|
2086
|
+
ret.put("message", message);
|
|
2087
|
+
ret.put("statusCode", statusCode);
|
|
2088
|
+
ret.put("version", version);
|
|
2089
|
+
ret.put("bundle", InternalUtils.mapToJSObject(current.toJSONMap()));
|
|
2090
|
+
this.notifyListeners("updateCheckResult", ret);
|
|
2091
|
+
}
|
|
2092
|
+
|
|
2003
2093
|
private void ensureBridgeSet() {
|
|
2004
2094
|
if (this.bridge != null && this.bridge.getWebView() != null) {
|
|
2005
2095
|
logger.setBridge(this.bridge);
|
|
@@ -2109,30 +2199,37 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
2109
2199
|
final BundleInfo current = CapacitorUpdaterPlugin.this.implementation.getCurrentBundle();
|
|
2110
2200
|
|
|
2111
2201
|
// Handle network errors and other failures first
|
|
2112
|
-
if (jsRes.has("error")) {
|
|
2113
|
-
String error = jsRes.getString("error");
|
|
2202
|
+
if (jsRes.has("error") || jsRes.has("kind")) {
|
|
2203
|
+
String error = jsRes.has("error") ? jsRes.getString("error") : "";
|
|
2114
2204
|
String errorMessage = jsRes.has("message") ? jsRes.getString("message") : "server did not provide a message";
|
|
2115
2205
|
int statusCode = jsRes.has("statusCode") ? jsRes.optInt("statusCode", 0) : 0;
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
logger.error(
|
|
2119
|
-
"getLatest failed with error: " + error + ", message: " + errorMessage + ", statusCode: " + statusCode
|
|
2120
|
-
);
|
|
2206
|
+
String kind = CapacitorUpdaterPlugin.this.getUpdateResponseKind(jsRes.has("kind") ? jsRes.getString("kind") : null);
|
|
2121
2207
|
String latestVersion = jsRes.has("version") ? jsRes.getString("version") : current.getVersionName();
|
|
2208
|
+
CapacitorUpdaterPlugin.this.notifyUpdateCheckResult(kind, error, errorMessage, statusCode, latestVersion, current);
|
|
2122
2209
|
|
|
2210
|
+
if ("up_to_date".equals(kind)) {
|
|
2211
|
+
logger.info("No new version available");
|
|
2212
|
+
} else if ("blocked".equals(kind)) {
|
|
2213
|
+
logger.info("Update check blocked with error: " + error);
|
|
2214
|
+
} else {
|
|
2215
|
+
logger.error(
|
|
2216
|
+
"getLatest failed with error: " + error + ", message: " + errorMessage + ", statusCode: " + statusCode
|
|
2217
|
+
);
|
|
2218
|
+
}
|
|
2219
|
+
|
|
2220
|
+
boolean isFailure = "failed".equals(kind);
|
|
2123
2221
|
CapacitorUpdaterPlugin.this.endBackGroundTaskWithNotif(
|
|
2124
2222
|
errorMessage,
|
|
2125
2223
|
latestVersion,
|
|
2126
2224
|
current,
|
|
2127
|
-
|
|
2225
|
+
isFailure,
|
|
2128
2226
|
plannedDirectUpdate,
|
|
2129
2227
|
"download_fail",
|
|
2130
2228
|
"downloadFailed",
|
|
2131
|
-
|
|
2229
|
+
isFailure
|
|
2132
2230
|
);
|
|
2133
2231
|
return;
|
|
2134
2232
|
}
|
|
2135
|
-
|
|
2136
2233
|
try {
|
|
2137
2234
|
final String latestVersionName = jsRes.getString("version");
|
|
2138
2235
|
|
|
@@ -2438,12 +2535,14 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
2438
2535
|
|
|
2439
2536
|
@Override
|
|
2440
2537
|
public void run() {
|
|
2538
|
+
final Thread currentThread = Thread.currentThread();
|
|
2441
2539
|
try {
|
|
2442
2540
|
logger.info("Wait for " + this.waitTimeMs + "ms, then check for notifyAppReady");
|
|
2443
2541
|
Thread.sleep(this.waitTimeMs);
|
|
2444
2542
|
CapacitorUpdaterPlugin.this.checkRevert();
|
|
2445
|
-
CapacitorUpdaterPlugin.this.
|
|
2543
|
+
CapacitorUpdaterPlugin.this.clearAppReadyCheckIfCurrent(currentThread);
|
|
2446
2544
|
} catch (final InterruptedException e) {
|
|
2545
|
+
CapacitorUpdaterPlugin.this.clearAppReadyCheckIfCurrent(currentThread);
|
|
2447
2546
|
logger.info(DeferredNotifyAppReadyCheck.class.getName() + " was interrupted.");
|
|
2448
2547
|
}
|
|
2449
2548
|
}
|