@capawesome/capacitor-live-update 8.1.1 → 8.2.1-dev.70823ec8.1778138208
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/CapawesomeCapacitorLiveUpdate.podspec +15 -0
- package/Package.swift +21 -5
- package/README.md +147 -3
- package/android/build.gradle +7 -0
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/liveupdate/LiveUpdate.java +104 -2
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/liveupdate/LiveUpdateHttpClient.java +12 -1
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/liveupdate/LiveUpdatePlugin.java +39 -1
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/liveupdate/classes/api/GetChannelsResponseItem.java +28 -0
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/liveupdate/classes/options/FetchChannelsOptions.java +38 -0
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/liveupdate/classes/options/FetchLatestBundleOptions.java +15 -0
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/liveupdate/classes/results/ChannelResult.java +28 -0
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/liveupdate/classes/results/FetchChannelsResult.java +28 -0
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/liveupdate/classes/results/FetchLatestBundleResult.java +30 -0
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/liveupdate/providers/ionic/LiveUpdateIonicManager.java +232 -0
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/liveupdate/providers/ionic/LiveUpdateIonicProvider.java +41 -0
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/liveupdate/providers/ionic/LiveUpdateIonicProviderRegistration.java +46 -0
- package/dist/docs.json +151 -3
- package/dist/esm/definitions.d.ts +85 -0
- package/dist/esm/definitions.js.map +1 -1
- package/dist/esm/web.d.ts +2 -1
- package/dist/esm/web.js +3 -0
- package/dist/esm/web.js.map +1 -1
- package/dist/plugin.cjs.js +3 -0
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +3 -0
- package/dist/plugin.js.map +1 -1
- package/ios/Plugin/Classes/Options/FetchChannelsOptions.swift +26 -0
- package/ios/Plugin/Classes/Options/FetchLatestBundleOptions.swift +12 -0
- package/ios/Plugin/Classes/Results/ChannelResult.swift +19 -0
- package/ios/Plugin/Classes/Results/FetchChannelsResult.swift +16 -0
- package/ios/Plugin/Classes/Results/FetchLatestBundleResult.swift +24 -0
- package/ios/Plugin/Enums/CustomError.swift +12 -0
- package/ios/Plugin/LiveUpdate.swift +55 -1
- package/ios/Plugin/LiveUpdateHttpClient.swift +11 -0
- package/ios/Plugin/LiveUpdatePlugin.swift +40 -1
- package/ios/Plugin/Protocols/Api/GetChannelsResponseItem.swift +4 -0
- package/ios/Plugin/Providers/Ionic/LiveUpdateIonicManager.swift +118 -0
- package/ios/Plugin/Providers/Ionic/LiveUpdateIonicProvider.swift +25 -0
- package/package.json +1 -3
|
@@ -17,4 +17,19 @@ Pod::Spec.new do |s|
|
|
|
17
17
|
s.dependency 'ZIPFoundation', '~> 0.9.0'
|
|
18
18
|
s.swift_version = '5.1'
|
|
19
19
|
s.static_framework = true
|
|
20
|
+
s.default_subspec = 'Default'
|
|
21
|
+
|
|
22
|
+
s.subspec 'Default' do |ss|
|
|
23
|
+
# Default subspec
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Opt-in subspec that pulls in the Ionic Live Update Provider SDK and
|
|
27
|
+
# compiles in the provider/manager classes guarded by
|
|
28
|
+
# `#if CAPAWESOME_INCLUDE_IONIC_PROVIDER`.
|
|
29
|
+
s.subspec 'IonicProvider' do |ss|
|
|
30
|
+
ss.dependency 'LiveUpdateProvider', '0.1.0-alpha.2'
|
|
31
|
+
ss.pod_target_xcconfig = {
|
|
32
|
+
'OTHER_SWIFT_FLAGS' => '$(inherited) -DCAPAWESOME_INCLUDE_IONIC_PROVIDER'
|
|
33
|
+
}
|
|
34
|
+
end
|
|
20
35
|
end
|
package/Package.swift
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// swift-tools-version:
|
|
1
|
+
// swift-tools-version: 6.1
|
|
2
2
|
import PackageDescription
|
|
3
3
|
|
|
4
4
|
let package = Package(
|
|
@@ -9,10 +9,17 @@ let package = Package(
|
|
|
9
9
|
name: "CapawesomeCapacitorLiveUpdate",
|
|
10
10
|
targets: ["LiveUpdatePlugin"])
|
|
11
11
|
],
|
|
12
|
+
traits: [
|
|
13
|
+
.trait(
|
|
14
|
+
name: "IonicProvider",
|
|
15
|
+
description: "Enables registration with the Ionic Live Update Provider SDK."
|
|
16
|
+
)
|
|
17
|
+
],
|
|
12
18
|
dependencies: [
|
|
13
19
|
.package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", from: "8.0.0"),
|
|
14
20
|
.package(url: "https://github.com/Alamofire/Alamofire.git", .upToNextMinor(from: "5.10.2")),
|
|
15
|
-
.package(url: "https://github.com/weichsel/ZIPFoundation.git", .upToNextMinor(from: "0.9.0"))
|
|
21
|
+
.package(url: "https://github.com/weichsel/ZIPFoundation.git", .upToNextMinor(from: "0.9.0")),
|
|
22
|
+
.package(url: "https://github.com/ionic-team/live-update-provider-sdk.git", exact: "0.1.0-alpha.2")
|
|
16
23
|
],
|
|
17
24
|
targets: [
|
|
18
25
|
.target(
|
|
@@ -21,12 +28,21 @@ let package = Package(
|
|
|
21
28
|
.product(name: "Capacitor", package: "capacitor-swift-pm"),
|
|
22
29
|
.product(name: "Cordova", package: "capacitor-swift-pm"),
|
|
23
30
|
.product(name: "Alamofire", package: "Alamofire"),
|
|
24
|
-
.product(name: "ZIPFoundation", package: "ZIPFoundation")
|
|
31
|
+
.product(name: "ZIPFoundation", package: "ZIPFoundation"),
|
|
32
|
+
.product(
|
|
33
|
+
name: "LiveUpdateProvider",
|
|
34
|
+
package: "live-update-provider-sdk",
|
|
35
|
+
condition: .when(traits: ["IonicProvider"])
|
|
36
|
+
)
|
|
25
37
|
],
|
|
26
|
-
path: "ios/Plugin"
|
|
38
|
+
path: "ios/Plugin",
|
|
39
|
+
swiftSettings: [
|
|
40
|
+
.define("CAPAWESOME_INCLUDE_IONIC_PROVIDER", .when(traits: ["IonicProvider"]))
|
|
41
|
+
]),
|
|
27
42
|
.testTarget(
|
|
28
43
|
name: "LiveUpdatePluginTests",
|
|
29
44
|
dependencies: ["LiveUpdatePlugin"],
|
|
30
45
|
path: "ios/PluginTests")
|
|
31
|
-
]
|
|
46
|
+
],
|
|
47
|
+
swiftLanguageModes: [.v5]
|
|
32
48
|
)
|
package/README.md
CHANGED
|
@@ -21,19 +21,29 @@ We are proud to offer one of the most complete and feature-rich Capacitor plugin
|
|
|
21
21
|
- 🛟 **Rollback**: Reset the app to the default bundle if an incompatible bundle has been set.
|
|
22
22
|
- 🚀 **Rollout**: Gradually roll out new bundles to gather valuable feedback.
|
|
23
23
|
- 🔁 **Delta Updates**: Make your updates faster by only downloading changed files.
|
|
24
|
+
- ⚙️ **Runtime Configuration**: Update plugin configuration at runtime without rebuilding the app.
|
|
25
|
+
- 📡 **Update Lifecycle Events**: Track download progress, react to bundle changes, and detect reloads with auto-blocking of rolled back bundles.
|
|
26
|
+
- 🏠 **Self-Hosted Bundles**: Download bundles from any URL, no Capawesome Cloud dependency required.
|
|
27
|
+
- 🏷️ **Custom Properties**: Associate custom key-value metadata with bundles via Capawesome Cloud.
|
|
28
|
+
- 🌀 **Ionic Portals Support**: Power live updates for [Ionic Portals](https://ionic.io/docs/portals) via the [Ionic Live Update Provider SDK](https://github.com/ionic-team/live-update-provider-sdk).
|
|
29
|
+
- 🧩 **Federated Capacitor Support**: Power live updates for [Federated Capacitor](https://ionic.io/docs/portals/for-capacitor/overview) shells via the [Ionic Live Update Provider SDK](https://github.com/ionic-team/live-update-provider-sdk).
|
|
24
30
|
- 🔒 **Security**: Verify the authenticity and integrity of the bundle using a public key.
|
|
25
31
|
- ⚔️ **Battle-Tested**: Used in more than 1,000 projects to update apps on more than 20,000,000 devices.
|
|
26
32
|
- 🌐 **Open Source**: Licensed under the MIT License.
|
|
27
33
|
|
|
28
34
|
Missing a feature? Just [open an issue](https://github.com/capawesome-team/capacitor-plugins/issues) and we'll take a look!
|
|
29
35
|
|
|
36
|
+
## Newsletter
|
|
37
|
+
|
|
38
|
+
Stay up to date with the latest news and updates about the Capawesome, Capacitor, and Ionic ecosystem by subscribing to our [Capawesome Newsletter](https://cloud.capawesome.io/newsletter/).
|
|
39
|
+
|
|
30
40
|
## Compatibility
|
|
31
41
|
|
|
32
42
|
| Plugin Version | Capacitor Version | Status |
|
|
33
43
|
| -------------- | ----------------- | -------------- |
|
|
34
44
|
| 8.x.x | >=8.x.x | Active support |
|
|
35
45
|
| 7.x.x | 7.x.x | Maintenance |
|
|
36
|
-
| 6.x.x | 6.x.x |
|
|
46
|
+
| 6.x.x | 6.x.x | Maintenance |
|
|
37
47
|
| 5.x.x | 5.x.x | Deprecated |
|
|
38
48
|
|
|
39
49
|
## Guides
|
|
@@ -44,6 +54,21 @@ Missing a feature? Just [open an issue](https://github.com/capawesome-team/capac
|
|
|
44
54
|
|
|
45
55
|
## Installation
|
|
46
56
|
|
|
57
|
+
You can use our **AI-Assisted Setup** to install the plugin.
|
|
58
|
+
Add the [Capawesome Skills](https://github.com/capawesome-team/skills) to your AI tool using the following command:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
npx skills add capawesome-team/skills --skill capacitor-plugins
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Then use the following prompt:
|
|
65
|
+
|
|
66
|
+
```
|
|
67
|
+
Use the `capacitor-plugins` skill from `capawesome-team/skills` to install the `@capawesome/capacitor-live-update` plugin in my project.
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
If you prefer **Manual Setup**, install the plugin by running the following commands and follow the platform-specific instructions below:
|
|
71
|
+
|
|
47
72
|
```bash
|
|
48
73
|
npm install @capawesome/capacitor-live-update
|
|
49
74
|
npx cap sync
|
|
@@ -51,6 +76,21 @@ npx cap sync
|
|
|
51
76
|
|
|
52
77
|
### Android
|
|
53
78
|
|
|
79
|
+
#### Channel
|
|
80
|
+
|
|
81
|
+
If you are using [Versioned Channels](https://capawesome.io/cloud/live-updates/guides/best-practices/#versioned-channels), you can set a default channel directly in your native project by adding a string resource.
|
|
82
|
+
This allows you to tie the channel to the version code at build time.
|
|
83
|
+
|
|
84
|
+
Add the following to your app's `build.gradle` file:
|
|
85
|
+
|
|
86
|
+
```groovy
|
|
87
|
+
android {
|
|
88
|
+
defaultConfig {
|
|
89
|
+
resValue "string", "capawesome_live_update_default_channel", "production-" + defaultConfig.versionCode
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
54
94
|
#### Variables
|
|
55
95
|
|
|
56
96
|
If needed, you can define the following project variable in your app’s `variables.gradle` file to change the default version of the dependency:
|
|
@@ -62,6 +102,18 @@ This can be useful if you encounter dependency conflicts with other plugins in y
|
|
|
62
102
|
|
|
63
103
|
### iOS
|
|
64
104
|
|
|
105
|
+
#### Channel
|
|
106
|
+
|
|
107
|
+
If you are using [Versioned Channels](https://capawesome.io/cloud/live-updates/guides/best-practices/#versioned-channels), you can set a default channel directly in your native project by adding a key to your `Info.plist` file.
|
|
108
|
+
This allows you to tie the channel to the build version at build time.
|
|
109
|
+
|
|
110
|
+
Add the following to your `Info.plist` file:
|
|
111
|
+
|
|
112
|
+
```xml
|
|
113
|
+
<key>CapawesomeLiveUpdateDefaultChannel</key>
|
|
114
|
+
<string>production-$(CURRENT_PROJECT_VERSION)</string>
|
|
115
|
+
```
|
|
116
|
+
|
|
65
117
|
#### Privacy manifest
|
|
66
118
|
|
|
67
119
|
Add the `NSPrivacyAccessedAPICategoryUserDefaults` dictionary key to your [Privacy Manifest](https://capacitorjs.com/docs/ios/privacy-manifest) (usually `ios/App/PrivacyInfo.xcprivacy`):
|
|
@@ -89,6 +141,10 @@ Add the `NSPrivacyAccessedAPICategoryUserDefaults` dictionary key to your [Priva
|
|
|
89
141
|
|
|
90
142
|
We recommend to declare [`CA92.1`](https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_use_of_required_reason_api#4278401) as the reason for accessing the [`UserDefaults`](https://developer.apple.com/documentation/foundation/userdefaults) API.
|
|
91
143
|
|
|
144
|
+
## Ionic Live Update Provider SDK integration
|
|
145
|
+
|
|
146
|
+
This plugin can register itself as a provider for the [Ionic Live Update Provider SDK](https://github.com/ionic-team/live-update-provider-sdk), so that **Ionic Portals** and **Federated Capacitor** apps can use Capawesome Cloud to deliver live updates. See [the full setup guide](https://github.com/capawesome-team/capacitor-plugins/blob/main/packages/live-update/docs/ionic-live-update-provider-sdk-integration.md) for details.
|
|
147
|
+
|
|
92
148
|
## Configuration
|
|
93
149
|
|
|
94
150
|
<docgen-config>
|
|
@@ -100,7 +156,7 @@ We recommend to declare [`CA92.1`](https://developer.apple.com/documentation/bun
|
|
|
100
156
|
| **`autoBlockRolledBackBundles`** | <code>boolean</code> | Whether or not to automatically block bundles that have been rolled back. When enabled, the plugin will automatically block bundles that caused a rollback (up to 100 bundles). When the limit is reached, the oldest blocked bundle is unblocked. Blocked bundles will be skipped in future sync operations. **Attention**: This option has no effect if `readyTimeout` is set to `0`. Only available on Android and iOS. | <code>false</code> | 7.3.0 |
|
|
101
157
|
| **`autoDeleteBundles`** | <code>boolean</code> | Whether or not to automatically delete unused bundles. When enabled, the plugin will automatically delete unused bundles after calling `ready()`. | <code>false</code> | 5.0.0 |
|
|
102
158
|
| **`autoUpdateStrategy`** | <code>'none' \| 'background'</code> | The auto-update strategy for live updates. - `none`: Live updates will not be applied automatically. - `background`: Live updates will be automatically downloaded and applied in the background at app startup and when the app resumes (if the last check was more than 15 minutes ago). Only available on Android and iOS. | <code>'none'</code> | 7.3.0 |
|
|
103
|
-
| **`defaultChannel`** | <code>string</code> | The default channel of the app.
|
|
159
|
+
| **`defaultChannel`** | <code>string</code> | The default channel of the app. This can be overridden by `setChannel()`, the `channel` parameter of `sync()`, or the native channel configuration (`CapawesomeLiveUpdateDefaultChannel` in `Info.plist` on iOS or `capawesome_live_update_default_channel` in `strings.xml` on Android). | | 6.3.0 |
|
|
104
160
|
| **`httpTimeout`** | <code>number</code> | The timeout in milliseconds for HTTP requests. | <code>60000</code> | 6.4.0 |
|
|
105
161
|
| **`publicKey`** | <code>string</code> | The public key to verify the integrity of the bundle. The public key must be a PEM-encoded RSA public key. | | 6.1.0 |
|
|
106
162
|
| **`readyTimeout`** | <code>number</code> | The timeout in milliseconds to wait for the app to be ready before resetting to the default bundle. It is strongly **recommended** to configure this option (e.g. `10000` ms) so that the plugin can roll back to the default bundle in case of problems. If configured, the plugin will wait for the app to call the `ready()` method before resetting to the default bundle. Set to `0` to disable the timeout. | <code>0</code> | 5.0.0 |
|
|
@@ -169,6 +225,11 @@ const downloadBundle = async () => {
|
|
|
169
225
|
await LiveUpdate.downloadBundle({ url: 'https://example.com/1.0.0.zip', bundleId: '1.0.0' });
|
|
170
226
|
};
|
|
171
227
|
|
|
228
|
+
const fetchChannels = async () => {
|
|
229
|
+
const result = await LiveUpdate.fetchChannels();
|
|
230
|
+
return result.channels;
|
|
231
|
+
};
|
|
232
|
+
|
|
172
233
|
const fetchLatestBundle = async () => {
|
|
173
234
|
await LiveUpdate.fetchLatestBundle();
|
|
174
235
|
};
|
|
@@ -273,6 +334,7 @@ const isNewBundleAvailable = async () => {
|
|
|
273
334
|
* [`clearBlockedBundles()`](#clearblockedbundles)
|
|
274
335
|
* [`deleteBundle(...)`](#deletebundle)
|
|
275
336
|
* [`downloadBundle(...)`](#downloadbundle)
|
|
337
|
+
* [`fetchChannels(...)`](#fetchchannels)
|
|
276
338
|
* [`fetchLatestBundle(...)`](#fetchlatestbundle)
|
|
277
339
|
* [`getBlockedBundles()`](#getblockedbundles)
|
|
278
340
|
* [`getBundles()`](#getbundles)
|
|
@@ -363,6 +425,35 @@ Only available on Android and iOS.
|
|
|
363
425
|
--------------------
|
|
364
426
|
|
|
365
427
|
|
|
428
|
+
### fetchChannels(...)
|
|
429
|
+
|
|
430
|
+
```typescript
|
|
431
|
+
fetchChannels(options?: FetchChannelsOptions | undefined) => Promise<FetchChannelsResult>
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
Fetch channels from [Capawesome Cloud](https://capawesome.io/cloud/).
|
|
435
|
+
|
|
436
|
+
This is primarily intended for development and QA purposes.
|
|
437
|
+
It allows you to retrieve a list of available channels so you can
|
|
438
|
+
dynamically switch between them using `setChannel(...)`.
|
|
439
|
+
|
|
440
|
+
**Attention**: Only works for apps with public channels enabled.
|
|
441
|
+
If channels are private, they can still be set using `setChannel(...)`
|
|
442
|
+
but won't be returned by this method.
|
|
443
|
+
|
|
444
|
+
Only available on Android and iOS.
|
|
445
|
+
|
|
446
|
+
| Param | Type |
|
|
447
|
+
| ------------- | --------------------------------------------------------------------- |
|
|
448
|
+
| **`options`** | <code><a href="#fetchchannelsoptions">FetchChannelsOptions</a></code> |
|
|
449
|
+
|
|
450
|
+
**Returns:** <code>Promise<<a href="#fetchchannelsresult">FetchChannelsResult</a>></code>
|
|
451
|
+
|
|
452
|
+
**Since:** 8.2.0
|
|
453
|
+
|
|
454
|
+
--------------------
|
|
455
|
+
|
|
456
|
+
|
|
366
457
|
### fetchLatestBundle(...)
|
|
367
458
|
|
|
368
459
|
```typescript
|
|
@@ -429,6 +520,15 @@ getChannel() => Promise<GetChannelResult>
|
|
|
429
520
|
|
|
430
521
|
Get the channel that is used for the update.
|
|
431
522
|
|
|
523
|
+
The channel is resolved in the following order (highest priority first):
|
|
524
|
+
1. `setChannel()` (SharedPreferences on Android / UserDefaults on iOS)
|
|
525
|
+
2. Native config (`CapawesomeLiveUpdateDefaultChannel` in `Info.plist` on iOS or
|
|
526
|
+
`capawesome_live_update_default_channel` in `strings.xml` on Android)
|
|
527
|
+
3. Capacitor config `defaultChannel`
|
|
528
|
+
|
|
529
|
+
**Note**: The `channel` parameter of `sync()` takes the highest priority
|
|
530
|
+
but is not persisted and therefore not returned by this method.
|
|
531
|
+
|
|
432
532
|
Only available on Android and iOS.
|
|
433
533
|
|
|
434
534
|
**Returns:** <code>Promise<<a href="#getchannelresult">GetChannelResult</a>></code>
|
|
@@ -891,12 +991,36 @@ Remove all listeners for this plugin.
|
|
|
891
991
|
| **`url`** | <code>string</code> | The URL of the bundle to download. For the `zip` artifact type, the URL must point to a ZIP file. For the `manifest` artifact type, the URL serves as the base URL to download the individual files. For example, if the URL is `https://example.com/download`, the plugin will download the file with the href `index.html` from `https://example.com/download?href=index.html`. To **verify the integrity** of the file, the server should return a `X-Checksum` header with the SHA-256 hash in hex format. To **verify the signature** of the file, the server should return a `X-Signature` header with the signed SHA-256 hash in base64 format. | | 5.0.0 |
|
|
892
992
|
|
|
893
993
|
|
|
994
|
+
#### FetchChannelsResult
|
|
995
|
+
|
|
996
|
+
| Prop | Type | Description | Since |
|
|
997
|
+
| -------------- | ---------------------- | --------------------- | ----- |
|
|
998
|
+
| **`channels`** | <code>Channel[]</code> | The list of channels. | 8.2.0 |
|
|
999
|
+
|
|
1000
|
+
|
|
1001
|
+
#### Channel
|
|
1002
|
+
|
|
1003
|
+
| Prop | Type | Description | Since |
|
|
1004
|
+
| ---------- | ------------------- | ------------------------------------- | ----- |
|
|
1005
|
+
| **`id`** | <code>string</code> | The unique identifier of the channel. | 8.2.0 |
|
|
1006
|
+
| **`name`** | <code>string</code> | The name of the channel. | 8.2.0 |
|
|
1007
|
+
|
|
1008
|
+
|
|
1009
|
+
#### FetchChannelsOptions
|
|
1010
|
+
|
|
1011
|
+
| Prop | Type | Description | Default | Since |
|
|
1012
|
+
| ------------ | ------------------- | ----------------------------------------- | --------------- | ----- |
|
|
1013
|
+
| **`limit`** | <code>number</code> | The maximum number of channels to return. | <code>50</code> | 8.2.0 |
|
|
1014
|
+
| **`offset`** | <code>number</code> | The number of channels to skip. | <code>0</code> | 8.2.0 |
|
|
1015
|
+
| **`query`** | <code>string</code> | The query to filter channels by name. | | 8.2.0 |
|
|
1016
|
+
|
|
1017
|
+
|
|
894
1018
|
#### FetchLatestBundleResult
|
|
895
1019
|
|
|
896
1020
|
| Prop | Type | Description | Since |
|
|
897
1021
|
| ---------------------- | --------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----- |
|
|
898
1022
|
| **`artifactType`** | <code>'manifest' \| 'zip'</code> | The artifact type of the bundle. | 6.7.0 |
|
|
899
|
-
| **`bundleId`** | <code>string \| null</code> | The unique identifier of the latest bundle. If `null`, no bundle is available.
|
|
1023
|
+
| **`bundleId`** | <code>string \| null</code> | The unique identifier of the latest bundle. On Capawesome Cloud, this is the ID of the app build artifact. If `null`, no bundle is available. | 6.6.0 |
|
|
900
1024
|
| **`checksum`** | <code>string</code> | The checksum of the latest bundle if the bundle is self-hosted. If the bundle is hosted on Capawesome Cloud, the checksum will be returned as response header when downloading the bundle. | 7.1.0 |
|
|
901
1025
|
| **`customProperties`** | <code>{ [key: string]: string; }</code> | Custom properties that are associated with the latest bundle. | 7.0.0 |
|
|
902
1026
|
| **`downloadUrl`** | <code>string</code> | The URL of the latest bundle to download. Pass this URL to the `downloadBundle(...)` method to download the bundle. | 6.7.0 |
|
|
@@ -1129,6 +1253,26 @@ For this reason, you must be careful to [restrict live updates to compatible nat
|
|
|
1129
1253
|
|
|
1130
1254
|
## FAQ
|
|
1131
1255
|
|
|
1256
|
+
### What is a bundle?
|
|
1257
|
+
|
|
1258
|
+
A bundle is a set of web assets (HTML, CSS, JavaScript, etc.) that make up your app's user interface.
|
|
1259
|
+
The plugin manages two types of bundles: the **built-in bundle** that ships with the native app binary, and **live update bundles** that are downloaded at runtime to update the app without a native release.
|
|
1260
|
+
Each live update bundle has a unique **bundle ID** returned by the [`fetchLatestBundle(...)`](#fetchlatestbundle) method.
|
|
1261
|
+
On Capawesome Cloud, the bundle ID corresponds to the ID of the app build artifact.
|
|
1262
|
+
|
|
1263
|
+
### How do I set a channel?
|
|
1264
|
+
|
|
1265
|
+
There are four ways to set a channel, listed from lowest to highest priority:
|
|
1266
|
+
|
|
1267
|
+
1. **Capacitor config**: Set the `defaultChannel` property in the [plugin configuration](#configuration). This is the simplest way to set a static default channel.
|
|
1268
|
+
2. **Native config**: Set `CapawesomeLiveUpdateDefaultChannel` in `Info.plist` (iOS) or `capawesome_live_update_default_channel` in `strings.xml` (Android). This is useful for [Versioned Channels](https://capawesome.io/cloud/live-updates/guides/best-practices/#versioned-channels) where the channel is tied to the build version.
|
|
1269
|
+
3. **[`setChannel(...)`](#setchannel)**: Set the channel at runtime. The value is persisted across app restarts.
|
|
1270
|
+
4. **[`sync(...)`](#sync)**: Pass a `channel` option to override the channel for a single sync call. This does **not** persist the channel.
|
|
1271
|
+
|
|
1272
|
+
Each method overrides the ones above it. You can check the currently resolved channel by calling [`getChannel()`](#getchannel).
|
|
1273
|
+
|
|
1274
|
+
Additionally, Capawesome Cloud supports [forced channel assignments](https://capawesome.io/blog/capawesome-cloud-forced-channel-assignments/) which allow you to override the channel for a specific device without any app code changes. Please note that forced channel assignments have a higher priority than all of the above methods and should be used with caution.
|
|
1275
|
+
|
|
1132
1276
|
### Why can't I see my changes during development?
|
|
1133
1277
|
|
|
1134
1278
|
As soon as you have installed a live update, the app will use the live update bundle and no longer the default bundle.
|
package/android/build.gradle
CHANGED
|
@@ -5,6 +5,8 @@ ext {
|
|
|
5
5
|
androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.7.0'
|
|
6
6
|
okhttp3Version = project.hasProperty('okhttp3Version') ? rootProject.ext.okhttp3Version : '5.3.2'
|
|
7
7
|
zip4jVersion = project.hasProperty('zip4jVersion') ? rootProject.ext.zip4jVersion : '2.11.5'
|
|
8
|
+
capawesomeCapacitorLiveUpdateIncludeIonicProvider = project.hasProperty('capawesomeCapacitorLiveUpdateIncludeIonicProvider') ? rootProject.ext.capawesomeCapacitorLiveUpdateIncludeIonicProvider : false
|
|
9
|
+
ionicLiveUpdateProviderVersion = project.hasProperty('ionicLiveUpdateProviderVersion') ? rootProject.ext.ionicLiveUpdateProviderVersion : '0.1.0-alpha.2'
|
|
8
10
|
}
|
|
9
11
|
|
|
10
12
|
buildscript {
|
|
@@ -56,6 +58,11 @@ dependencies {
|
|
|
56
58
|
implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion"
|
|
57
59
|
implementation "net.lingala.zip4j:zip4j:$zip4jVersion"
|
|
58
60
|
implementation "com.squareup.okhttp3:okhttp:$okhttp3Version"
|
|
61
|
+
if (capawesomeCapacitorLiveUpdateIncludeIonicProvider) {
|
|
62
|
+
implementation "io.ionic:liveupdateprovider:$ionicLiveUpdateProviderVersion"
|
|
63
|
+
} else {
|
|
64
|
+
compileOnly "io.ionic:liveupdateprovider:$ionicLiveUpdateProviderVersion"
|
|
65
|
+
}
|
|
59
66
|
testImplementation "junit:junit:$junitVersion"
|
|
60
67
|
androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion"
|
|
61
68
|
androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion"
|
|
@@ -15,17 +15,21 @@ import com.getcapacitor.Logger;
|
|
|
15
15
|
import com.getcapacitor.plugin.WebView;
|
|
16
16
|
import io.capawesome.capacitorjs.plugins.liveupdate.classes.Manifest;
|
|
17
17
|
import io.capawesome.capacitorjs.plugins.liveupdate.classes.ManifestItem;
|
|
18
|
+
import io.capawesome.capacitorjs.plugins.liveupdate.classes.api.GetChannelsResponseItem;
|
|
18
19
|
import io.capawesome.capacitorjs.plugins.liveupdate.classes.api.GetLatestBundleResponse;
|
|
19
20
|
import io.capawesome.capacitorjs.plugins.liveupdate.classes.events.DownloadBundleProgressEvent;
|
|
20
21
|
import io.capawesome.capacitorjs.plugins.liveupdate.classes.events.NextBundleSetEvent;
|
|
21
22
|
import io.capawesome.capacitorjs.plugins.liveupdate.classes.options.DeleteBundleOptions;
|
|
22
23
|
import io.capawesome.capacitorjs.plugins.liveupdate.classes.options.DownloadBundleOptions;
|
|
24
|
+
import io.capawesome.capacitorjs.plugins.liveupdate.classes.options.FetchChannelsOptions;
|
|
23
25
|
import io.capawesome.capacitorjs.plugins.liveupdate.classes.options.FetchLatestBundleOptions;
|
|
24
26
|
import io.capawesome.capacitorjs.plugins.liveupdate.classes.options.SetChannelOptions;
|
|
25
27
|
import io.capawesome.capacitorjs.plugins.liveupdate.classes.options.SetConfigOptions;
|
|
26
28
|
import io.capawesome.capacitorjs.plugins.liveupdate.classes.options.SetCustomIdOptions;
|
|
27
29
|
import io.capawesome.capacitorjs.plugins.liveupdate.classes.options.SetNextBundleOptions;
|
|
28
30
|
import io.capawesome.capacitorjs.plugins.liveupdate.classes.options.SyncOptions;
|
|
31
|
+
import io.capawesome.capacitorjs.plugins.liveupdate.classes.results.ChannelResult;
|
|
32
|
+
import io.capawesome.capacitorjs.plugins.liveupdate.classes.results.FetchChannelsResult;
|
|
29
33
|
import io.capawesome.capacitorjs.plugins.liveupdate.classes.results.FetchLatestBundleResult;
|
|
30
34
|
import io.capawesome.capacitorjs.plugins.liveupdate.classes.results.GetBlockedBundlesResult;
|
|
31
35
|
import io.capawesome.capacitorjs.plugins.liveupdate.classes.results.GetBundlesResult;
|
|
@@ -65,6 +69,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|
|
65
69
|
import java.util.concurrent.atomic.AtomicLong;
|
|
66
70
|
import java.util.concurrent.atomic.AtomicReference;
|
|
67
71
|
import net.lingala.zip4j.ZipFile;
|
|
72
|
+
import net.lingala.zip4j.model.FileHeader;
|
|
68
73
|
import okhttp3.Call;
|
|
69
74
|
import okhttp3.HttpUrl;
|
|
70
75
|
import okhttp3.Response;
|
|
@@ -115,6 +120,9 @@ public class LiveUpdate {
|
|
|
115
120
|
// Check version and reset config if version changed
|
|
116
121
|
checkAndResetConfigIfVersionChanged();
|
|
117
122
|
|
|
123
|
+
// Set the device ID on the HTTP client (after any potential config reset)
|
|
124
|
+
this.httpClient.setDeviceId(getDeviceId());
|
|
125
|
+
|
|
118
126
|
// Start the rollback timer to rollback to the default bundle
|
|
119
127
|
// if the app is not ready after a certain time
|
|
120
128
|
startRollbackTimer();
|
|
@@ -159,6 +167,63 @@ public class LiveUpdate {
|
|
|
159
167
|
}
|
|
160
168
|
}
|
|
161
169
|
|
|
170
|
+
public void fetchChannels(@NonNull FetchChannelsOptions options, @NonNull NonEmptyCallback<FetchChannelsResult> callback) {
|
|
171
|
+
try {
|
|
172
|
+
HttpUrl.Builder urlBuilder = new HttpUrl.Builder()
|
|
173
|
+
.scheme("https")
|
|
174
|
+
.host(config.getServerDomain())
|
|
175
|
+
.addPathSegment("v1")
|
|
176
|
+
.addPathSegment("apps")
|
|
177
|
+
.addPathSegment(getAppId())
|
|
178
|
+
.addPathSegment("channels");
|
|
179
|
+
if (options.getLimit() != null) {
|
|
180
|
+
urlBuilder.addQueryParameter("limit", String.valueOf(options.getLimit()));
|
|
181
|
+
}
|
|
182
|
+
if (options.getOffset() != null) {
|
|
183
|
+
urlBuilder.addQueryParameter("offset", String.valueOf(options.getOffset()));
|
|
184
|
+
}
|
|
185
|
+
if (options.getQuery() != null) {
|
|
186
|
+
urlBuilder.addQueryParameter("query", options.getQuery());
|
|
187
|
+
}
|
|
188
|
+
String url = urlBuilder.build().toString();
|
|
189
|
+
|
|
190
|
+
httpClient.enqueue(
|
|
191
|
+
url,
|
|
192
|
+
new NonEmptyCallback<Response>() {
|
|
193
|
+
@Override
|
|
194
|
+
public void success(@NonNull Response response) {
|
|
195
|
+
try {
|
|
196
|
+
String responseBodyString = response.body().string();
|
|
197
|
+
if (response.isSuccessful()) {
|
|
198
|
+
JSONArray responseJsonArray = new JSONArray(responseBodyString);
|
|
199
|
+
ChannelResult[] channels = new ChannelResult[responseJsonArray.length()];
|
|
200
|
+
for (int i = 0; i < responseJsonArray.length(); i++) {
|
|
201
|
+
GetChannelsResponseItem item = new GetChannelsResponseItem(responseJsonArray.getJSONObject(i));
|
|
202
|
+
channels[i] = new ChannelResult(item.getId(), item.getName());
|
|
203
|
+
}
|
|
204
|
+
FetchChannelsResult result = new FetchChannelsResult(channels);
|
|
205
|
+
callback.success(result);
|
|
206
|
+
} else if (response.code() == 401) {
|
|
207
|
+
callback.error(new Exception("Unauthorized. Channel Discovery may not be enabled for this app."));
|
|
208
|
+
} else {
|
|
209
|
+
callback.error(new Exception(responseBodyString));
|
|
210
|
+
}
|
|
211
|
+
} catch (Exception e) {
|
|
212
|
+
callback.error(e);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
@Override
|
|
217
|
+
public void error(@NonNull Exception exception) {
|
|
218
|
+
callback.error(exception);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
);
|
|
222
|
+
} catch (Exception e) {
|
|
223
|
+
callback.error(e);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
162
227
|
public void fetchLatestBundle(@NonNull FetchLatestBundleOptions options, @NonNull NonEmptyCallback<FetchLatestBundleResult> callback) {
|
|
163
228
|
fetchLatestBundleInternal(
|
|
164
229
|
options,
|
|
@@ -233,6 +298,17 @@ public class LiveUpdate {
|
|
|
233
298
|
callback.success(result);
|
|
234
299
|
}
|
|
235
300
|
|
|
301
|
+
/**
|
|
302
|
+
* @return The on-disk directory of a downloaded bundle, or `null` if the bundle does not exist.
|
|
303
|
+
*/
|
|
304
|
+
@Nullable
|
|
305
|
+
public File getBundleDirectory(@NonNull String bundleId) {
|
|
306
|
+
if (!hasBundleById(bundleId)) {
|
|
307
|
+
return null;
|
|
308
|
+
}
|
|
309
|
+
return buildBundleDirectoryFor(bundleId);
|
|
310
|
+
}
|
|
311
|
+
|
|
236
312
|
public void getCustomId(@NonNull NonEmptyCallback callback) {
|
|
237
313
|
String customId = preferences.getCustomId();
|
|
238
314
|
GetCustomIdResult result = new GetCustomIdResult(customId);
|
|
@@ -907,13 +983,17 @@ public class LiveUpdate {
|
|
|
907
983
|
@NonNull NonEmptyCallback<GetLatestBundleResponse> callback
|
|
908
984
|
) {
|
|
909
985
|
try {
|
|
986
|
+
String appId = options.getAppId() == null ? getAppId() : options.getAppId();
|
|
987
|
+
if (appId == null || appId.isEmpty()) {
|
|
988
|
+
throw new Exception(LiveUpdatePlugin.ERROR_APP_ID_MISSING);
|
|
989
|
+
}
|
|
910
990
|
String channel = options.getChannel() == null ? getChannel() : options.getChannel();
|
|
911
991
|
String url = new HttpUrl.Builder()
|
|
912
992
|
.scheme("https")
|
|
913
993
|
.host(config.getServerDomain())
|
|
914
994
|
.addPathSegment("v1")
|
|
915
995
|
.addPathSegment("apps")
|
|
916
|
-
.addPathSegment(
|
|
996
|
+
.addPathSegment(appId)
|
|
917
997
|
.addPathSegment("bundles")
|
|
918
998
|
.addPathSegment("latest")
|
|
919
999
|
.addQueryParameter("appVersionCode", getVersionCodeAsString())
|
|
@@ -1015,12 +1095,28 @@ public class LiveUpdate {
|
|
|
1015
1095
|
if (config.getDefaultChannel() != null) {
|
|
1016
1096
|
channel = config.getDefaultChannel();
|
|
1017
1097
|
}
|
|
1098
|
+
String nativeChannel = getNativeChannel();
|
|
1099
|
+
if (nativeChannel != null) {
|
|
1100
|
+
channel = nativeChannel;
|
|
1101
|
+
}
|
|
1018
1102
|
if (preferences.getChannel() != null) {
|
|
1019
1103
|
channel = preferences.getChannel();
|
|
1020
1104
|
}
|
|
1021
1105
|
return channel;
|
|
1022
1106
|
}
|
|
1023
1107
|
|
|
1108
|
+
@Nullable
|
|
1109
|
+
private String getNativeChannel() {
|
|
1110
|
+
int resId = plugin
|
|
1111
|
+
.getContext()
|
|
1112
|
+
.getResources()
|
|
1113
|
+
.getIdentifier("capawesome_live_update_default_channel", "string", plugin.getContext().getPackageName());
|
|
1114
|
+
if (resId == 0) {
|
|
1115
|
+
return null;
|
|
1116
|
+
}
|
|
1117
|
+
return plugin.getContext().getResources().getString(resId);
|
|
1118
|
+
}
|
|
1119
|
+
|
|
1024
1120
|
/**
|
|
1025
1121
|
* @return The current bundle ID or `null` if the default bundle is in use.
|
|
1026
1122
|
*/
|
|
@@ -1352,7 +1448,13 @@ public class LiveUpdate {
|
|
|
1352
1448
|
private File unzipFile(@NonNull File zipFile) throws IOException {
|
|
1353
1449
|
File destination = buildTemporaryDirectory();
|
|
1354
1450
|
String destinationPath = destination.getPath();
|
|
1355
|
-
new ZipFile(zipFile)
|
|
1451
|
+
ZipFile zip = new ZipFile(zipFile);
|
|
1452
|
+
// Clear stored Unix permissions to prevent EACCES errors on newer Android versions
|
|
1453
|
+
// where restrictive directory permissions from the zip block file creation.
|
|
1454
|
+
for (FileHeader fileHeader : zip.getFileHeaders()) {
|
|
1455
|
+
fileHeader.setExternalFileAttributes(null);
|
|
1456
|
+
}
|
|
1457
|
+
zip.extractAll(destinationPath);
|
|
1356
1458
|
return destination;
|
|
1357
1459
|
}
|
|
1358
1460
|
|
package/android/src/main/java/io/capawesome/capacitorjs/plugins/liveupdate/LiveUpdateHttpClient.java
CHANGED
|
@@ -25,6 +25,9 @@ public class LiveUpdateHttpClient {
|
|
|
25
25
|
@NonNull
|
|
26
26
|
private final LiveUpdateConfig config;
|
|
27
27
|
|
|
28
|
+
@Nullable
|
|
29
|
+
private String deviceId;
|
|
30
|
+
|
|
28
31
|
@NonNull
|
|
29
32
|
private final OkHttpClient okHttpClient;
|
|
30
33
|
|
|
@@ -62,8 +65,16 @@ public class LiveUpdateHttpClient {
|
|
|
62
65
|
.build();
|
|
63
66
|
}
|
|
64
67
|
|
|
68
|
+
public void setDeviceId(@NonNull String deviceId) {
|
|
69
|
+
this.deviceId = deviceId;
|
|
70
|
+
}
|
|
71
|
+
|
|
65
72
|
public Call enqueue(String url, NonEmptyCallback<Response> callback) {
|
|
66
|
-
Request
|
|
73
|
+
Request.Builder builder = new Request.Builder().url(url);
|
|
74
|
+
if (deviceId != null) {
|
|
75
|
+
builder.addHeader("X-Capawesome-Device-Id", deviceId);
|
|
76
|
+
}
|
|
77
|
+
Request request = builder.build();
|
|
67
78
|
|
|
68
79
|
Call call = okHttpClient.newCall(request);
|
|
69
80
|
call.enqueue(
|
package/android/src/main/java/io/capawesome/capacitorjs/plugins/liveupdate/LiveUpdatePlugin.java
CHANGED
|
@@ -14,12 +14,14 @@ import io.capawesome.capacitorjs.plugins.liveupdate.classes.events.DownloadBundl
|
|
|
14
14
|
import io.capawesome.capacitorjs.plugins.liveupdate.classes.events.NextBundleSetEvent;
|
|
15
15
|
import io.capawesome.capacitorjs.plugins.liveupdate.classes.options.DeleteBundleOptions;
|
|
16
16
|
import io.capawesome.capacitorjs.plugins.liveupdate.classes.options.DownloadBundleOptions;
|
|
17
|
+
import io.capawesome.capacitorjs.plugins.liveupdate.classes.options.FetchChannelsOptions;
|
|
17
18
|
import io.capawesome.capacitorjs.plugins.liveupdate.classes.options.FetchLatestBundleOptions;
|
|
18
19
|
import io.capawesome.capacitorjs.plugins.liveupdate.classes.options.SetChannelOptions;
|
|
19
20
|
import io.capawesome.capacitorjs.plugins.liveupdate.classes.options.SetConfigOptions;
|
|
20
21
|
import io.capawesome.capacitorjs.plugins.liveupdate.classes.options.SetCustomIdOptions;
|
|
21
22
|
import io.capawesome.capacitorjs.plugins.liveupdate.classes.options.SetNextBundleOptions;
|
|
22
23
|
import io.capawesome.capacitorjs.plugins.liveupdate.classes.options.SyncOptions;
|
|
24
|
+
import io.capawesome.capacitorjs.plugins.liveupdate.classes.results.FetchChannelsResult;
|
|
23
25
|
import io.capawesome.capacitorjs.plugins.liveupdate.classes.results.FetchLatestBundleResult;
|
|
24
26
|
import io.capawesome.capacitorjs.plugins.liveupdate.classes.results.GetBlockedBundlesResult;
|
|
25
27
|
import io.capawesome.capacitorjs.plugins.liveupdate.classes.results.GetConfigResult;
|
|
@@ -30,14 +32,16 @@ import io.capawesome.capacitorjs.plugins.liveupdate.classes.results.IsSyncingRes
|
|
|
30
32
|
import io.capawesome.capacitorjs.plugins.liveupdate.interfaces.EmptyCallback;
|
|
31
33
|
import io.capawesome.capacitorjs.plugins.liveupdate.interfaces.NonEmptyCallback;
|
|
32
34
|
import io.capawesome.capacitorjs.plugins.liveupdate.interfaces.Result;
|
|
35
|
+
import io.capawesome.capacitorjs.plugins.liveupdate.providers.ionic.LiveUpdateIonicProviderRegistration;
|
|
33
36
|
|
|
34
37
|
@CapacitorPlugin(name = "LiveUpdate")
|
|
35
38
|
public class LiveUpdatePlugin extends Plugin {
|
|
36
39
|
|
|
37
40
|
public static final String TAG = "LiveUpdate";
|
|
38
|
-
public static final String VERSION = "8.
|
|
41
|
+
public static final String VERSION = "8.2.0";
|
|
39
42
|
public static final String SHARED_PREFERENCES_NAME = "CapawesomeLiveUpdate"; // DO NOT CHANGE
|
|
40
43
|
public static final String ERROR_APP_ID_MISSING = "appId must be configured.";
|
|
44
|
+
public static final String ERROR_BUNDLE_DIRECTORY_NOT_FOUND = "Bundle directory could not be resolved.";
|
|
41
45
|
public static final String ERROR_BUNDLE_EXISTS = "bundle already exists.";
|
|
42
46
|
public static final String ERROR_BUNDLE_ID_MISSING = "bundleId must be provided.";
|
|
43
47
|
public static final String ERROR_BUNDLE_INDEX_HTML_MISSING = "The bundle does not contain an index.html file.";
|
|
@@ -46,7 +50,9 @@ public class LiveUpdatePlugin extends Plugin {
|
|
|
46
50
|
public static final String ERROR_CHECKSUM_MISMATCH = "Checksum mismatch.";
|
|
47
51
|
public static final String ERROR_CUSTOM_ID_MISSING = "customId must be provided.";
|
|
48
52
|
public static final String ERROR_DOWNLOAD_FAILED = "Bundle could not be downloaded.";
|
|
53
|
+
public static final String ERROR_DOWNLOAD_URL_MISSING = "Bundle does not have a valid download URL.";
|
|
49
54
|
public static final String ERROR_HTTP_TIMEOUT = "Request timed out.";
|
|
55
|
+
public static final String ERROR_MANAGER_KEY_MISSING = "managerKey must be provided.";
|
|
50
56
|
public static final String ERROR_URL_MISSING = "url must be provided.";
|
|
51
57
|
public static final String ERROR_SIGNATURE_VERIFICATION_FAILED = "Signature verification failed.";
|
|
52
58
|
public static final String ERROR_PUBLIC_KEY_INVALID = "Invalid public key.";
|
|
@@ -69,6 +75,10 @@ public class LiveUpdatePlugin extends Plugin {
|
|
|
69
75
|
try {
|
|
70
76
|
config = getLiveUpdateConfig();
|
|
71
77
|
implementation = new LiveUpdate(config, this);
|
|
78
|
+
// Register the Ionic Live Update Provider when the optional SDK is on the classpath.
|
|
79
|
+
if (LiveUpdateIonicProviderRegistration.isAvailable()) {
|
|
80
|
+
LiveUpdateIonicProviderRegistration.tryRegister(implementation);
|
|
81
|
+
}
|
|
72
82
|
} catch (Exception exception) {
|
|
73
83
|
Logger.error(TAG, exception.getMessage(), exception);
|
|
74
84
|
}
|
|
@@ -178,6 +188,34 @@ public class LiveUpdatePlugin extends Plugin {
|
|
|
178
188
|
}
|
|
179
189
|
}
|
|
180
190
|
|
|
191
|
+
@PluginMethod
|
|
192
|
+
public void fetchChannels(PluginCall call) {
|
|
193
|
+
try {
|
|
194
|
+
String appId = config.getAppId();
|
|
195
|
+
if (appId == null || appId.isEmpty()) {
|
|
196
|
+
call.reject(ERROR_APP_ID_MISSING);
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
FetchChannelsOptions options = new FetchChannelsOptions(call);
|
|
201
|
+
NonEmptyCallback<FetchChannelsResult> callback = new NonEmptyCallback<>() {
|
|
202
|
+
@Override
|
|
203
|
+
public void success(FetchChannelsResult result) {
|
|
204
|
+
resolveCall(call, result.toJSObject());
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
@Override
|
|
208
|
+
public void error(Exception exception) {
|
|
209
|
+
rejectCall(call, exception);
|
|
210
|
+
}
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
implementation.fetchChannels(options, callback);
|
|
214
|
+
} catch (Exception exception) {
|
|
215
|
+
rejectCall(call, exception);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
181
219
|
@PluginMethod
|
|
182
220
|
public void fetchLatestBundle(PluginCall call) {
|
|
183
221
|
try {
|