@capawesome/capacitor-live-update 6.0.6 → 6.0.8
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 +11 -0
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/liveupdate/LiveUpdate.java +18 -8
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/liveupdate/LiveUpdatePlugin.java +1 -1
- package/dist/docs.json +1 -1
- package/dist/esm/definitions.d.ts +3 -0
- package/dist/esm/definitions.js.map +1 -1
- package/ios/Plugin/LiveUpdate.swift +25 -24
- package/ios/Plugin/LiveUpdatePlugin.swift +1 -1
- package/package.json +9 -2
package/README.md
CHANGED
|
@@ -11,6 +11,7 @@ Capacitor plugin to update your app remotely in real-time.
|
|
|
11
11
|
- 📺 **Channel Support**: Set a channel for the app to manage different versions.
|
|
12
12
|
- 🔄 **Auto Update**: Automatically download and set the latest bundle for the app.
|
|
13
13
|
- 🛟 **Rollback**: Reset the app to the default bundle if an incompatible bundle has been set.
|
|
14
|
+
- 🚀 **Rollout**: Gradually roll out new bundles to gather valuable feedback.
|
|
14
15
|
|
|
15
16
|
## Installation
|
|
16
17
|
|
|
@@ -116,6 +117,13 @@ export default config;
|
|
|
116
117
|
|
|
117
118
|
A working example can be found here: [robingenz/capacitor-plugin-demo](https://github.com/robingenz/capacitor-plugin-demo)
|
|
118
119
|
|
|
120
|
+
## Starter templates
|
|
121
|
+
|
|
122
|
+
The following starter templates are available:
|
|
123
|
+
|
|
124
|
+
- [Ionstarter Angular Firebase](https://ionstarter.dev/)
|
|
125
|
+
- [Ionstarter Angular SQLite](https://ionstarter.dev/)
|
|
126
|
+
|
|
119
127
|
## Guides
|
|
120
128
|
|
|
121
129
|
- [Announcing the Capacitor Live Update Plugin](https://capawesome.io/blog/announcing-the-capacitor-live-update-plugin/)
|
|
@@ -390,6 +398,9 @@ ready() => Promise<void>
|
|
|
390
398
|
|
|
391
399
|
Notify the plugin that the app is ready to use and no rollback is needed.
|
|
392
400
|
|
|
401
|
+
**Attention**: This method should be called as soon as the app is ready to use
|
|
402
|
+
to prevent the app from being reset to the default bundle.
|
|
403
|
+
|
|
393
404
|
Only available on Android and iOS.
|
|
394
405
|
|
|
395
406
|
**Since:** 5.0.0
|
|
@@ -164,9 +164,7 @@ public class LiveUpdate {
|
|
|
164
164
|
}
|
|
165
165
|
|
|
166
166
|
public void reload() {
|
|
167
|
-
String
|
|
168
|
-
String nextPath = getNextCapacitorServerPath();
|
|
169
|
-
String path = nextPath == null ? currentPath : nextPath;
|
|
167
|
+
String path = getNextCapacitorServerPath();
|
|
170
168
|
setCurrentCapacitorServerPath(path);
|
|
171
169
|
startRollbackTimer();
|
|
172
170
|
}
|
|
@@ -415,6 +413,7 @@ public class LiveUpdate {
|
|
|
415
413
|
.addQueryParameter("platform", "0")
|
|
416
414
|
.addQueryParameter("pluginVersion", LiveUpdatePlugin.VERSION)
|
|
417
415
|
.build();
|
|
416
|
+
Logger.debug(LiveUpdatePlugin.TAG, "Fetching latest bundle from " + url);
|
|
418
417
|
OkHttpClient client = new OkHttpClient();
|
|
419
418
|
okhttp3.Request request = new okhttp3.Request.Builder().url(url).build();
|
|
420
419
|
client
|
|
@@ -423,6 +422,7 @@ public class LiveUpdate {
|
|
|
423
422
|
new okhttp3.Callback() {
|
|
424
423
|
@Override
|
|
425
424
|
public void onFailure(@NonNull okhttp3.Call call, @NonNull IOException exception) {
|
|
425
|
+
Logger.error(LiveUpdatePlugin.TAG, exception.getMessage(), exception);
|
|
426
426
|
callback.error(exception);
|
|
427
427
|
}
|
|
428
428
|
|
|
@@ -472,6 +472,9 @@ public class LiveUpdate {
|
|
|
472
472
|
return bundleIds;
|
|
473
473
|
}
|
|
474
474
|
|
|
475
|
+
/**
|
|
476
|
+
* @return The current bundle ID (`public` for the built-in bundle).
|
|
477
|
+
*/
|
|
475
478
|
private String getCurrentBundleId() {
|
|
476
479
|
String currentPath = getCurrentCapacitorServerPath();
|
|
477
480
|
if (currentPath.equals(defaultWebAssetDir)) {
|
|
@@ -480,6 +483,9 @@ public class LiveUpdate {
|
|
|
480
483
|
return new File(currentPath).getName();
|
|
481
484
|
}
|
|
482
485
|
|
|
486
|
+
/**
|
|
487
|
+
* @return The absolute path to the current bundle directory (`public` for the built-in bundle).
|
|
488
|
+
*/
|
|
483
489
|
private String getCurrentCapacitorServerPath() {
|
|
484
490
|
return plugin.getBridge().getServerBasePath();
|
|
485
491
|
}
|
|
@@ -494,23 +500,27 @@ public class LiveUpdate {
|
|
|
494
500
|
return deviceId;
|
|
495
501
|
}
|
|
496
502
|
|
|
503
|
+
/**
|
|
504
|
+
* @return The next bundle ID (`public` for the built-in bundle).
|
|
505
|
+
*/
|
|
506
|
+
@NonNull
|
|
497
507
|
private String getNextBundleId() {
|
|
498
508
|
String nextPath = getNextCapacitorServerPath();
|
|
499
|
-
if (nextPath == null) {
|
|
500
|
-
return null;
|
|
501
|
-
}
|
|
502
509
|
if (nextPath.equals(defaultWebAssetDir)) {
|
|
503
510
|
return defaultWebAssetDir;
|
|
504
511
|
}
|
|
505
512
|
return new File(nextPath).getName();
|
|
506
513
|
}
|
|
507
514
|
|
|
508
|
-
|
|
515
|
+
/**
|
|
516
|
+
* @return The absolute path to the next bundle directory (`public` for the built-in bundle).
|
|
517
|
+
*/
|
|
518
|
+
@NonNull
|
|
509
519
|
private String getNextCapacitorServerPath() {
|
|
510
520
|
return plugin
|
|
511
521
|
.getContext()
|
|
512
522
|
.getSharedPreferences(WebView.WEBVIEW_PREFS_NAME, Activity.MODE_PRIVATE)
|
|
513
|
-
.getString(WebView.CAP_SERVER_PATH,
|
|
523
|
+
.getString(WebView.CAP_SERVER_PATH, defaultWebAssetDir);
|
|
514
524
|
}
|
|
515
525
|
|
|
516
526
|
private boolean hasBundle(@NonNull String bundleId) {
|
package/android/src/main/java/io/capawesome/capacitorjs/plugins/liveupdate/LiveUpdatePlugin.java
CHANGED
|
@@ -19,7 +19,7 @@ import io.capawesome.capacitorjs.plugins.liveupdate.interfaces.Result;
|
|
|
19
19
|
public class LiveUpdatePlugin extends Plugin {
|
|
20
20
|
|
|
21
21
|
public static final String TAG = "LiveUpdate";
|
|
22
|
-
public static final String VERSION = "6.0.
|
|
22
|
+
public static final String VERSION = "6.0.7";
|
|
23
23
|
public static final String SHARED_PREFERENCES_NAME = "CapawesomeLiveUpdate"; // DO NOT CHANGE
|
|
24
24
|
public static final String ERROR_APP_ID_MISSING = "appId must be configured.";
|
|
25
25
|
public static final String ERROR_BUNDLE_EXISTS = "bundle already exists.";
|
package/dist/docs.json
CHANGED
|
@@ -181,7 +181,7 @@
|
|
|
181
181
|
"text": "5.0.0"
|
|
182
182
|
}
|
|
183
183
|
],
|
|
184
|
-
"docs": "Notify the plugin that the app is ready to use and no rollback is needed.\n\nOnly available on Android and iOS.",
|
|
184
|
+
"docs": "Notify the plugin that the app is ready to use and no rollback is needed.\n\n**Attention**: This method should be called as soon as the app is ready to use\nto prevent the app from being reset to the default bundle.\n\nOnly available on Android and iOS.",
|
|
185
185
|
"complexTypes": [],
|
|
186
186
|
"slug": "ready"
|
|
187
187
|
},
|
|
@@ -117,6 +117,9 @@ export interface LiveUpdatePlugin {
|
|
|
117
117
|
/**
|
|
118
118
|
* Notify the plugin that the app is ready to use and no rollback is needed.
|
|
119
119
|
*
|
|
120
|
+
* **Attention**: This method should be called as soon as the app is ready to use
|
|
121
|
+
* to prevent the app from being reset to the default bundle.
|
|
122
|
+
*
|
|
120
123
|
* Only available on Android and iOS.
|
|
121
124
|
*
|
|
122
125
|
* @since 5.0.0
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"AAAA,wCAAwC","sourcesContent":["/// <reference types=\"@capacitor/cli\" />\n\ndeclare module '@capacitor/cli' {\n export interface PluginsConfig {\n LiveUpdate?: {\n /**\n * The app ID is used to identify the app when using [Capawesome Cloud](https://capawesome.io/cloud).\n *\n * @since 5.0.0\n * @example '4100e356-e851-47fe-9d3c-b411eb325a99'\n */\n appId?: string;\n /**\n * Whether or not to automatically delete unused bundles.\n *\n * When enabled, the plugin will automatically delete unused bundles after calling `ready()`.\n *\n * @since 5.0.0\n * @default false\n */\n autoDeleteBundles?: boolean;\n /**\n * Whether or not the plugin is enabled.\n *\n * @since 5.0.0\n * @default true\n */\n enabled?: boolean;\n /**\n * The timeout in milliseconds to wait for the app to be ready before resetting to the default bundle.\n *\n * @since 5.0.0\n * @default 10000\n */\n readyTimeout?: number;\n /**\n * Whether or not the app should be reset to the default bundle during an update.\n *\n * @since 5.0.0\n * @default true\n */\n resetOnUpdate?: boolean;\n };\n }\n}\n\nexport interface LiveUpdatePlugin {\n /**\n * Delete a bundle from the app.\n *\n * Only available on Android and iOS.\n *\n * @since 5.0.0\n */\n deleteBundle(options: DeleteBundleOptions): Promise<void>;\n /**\n * Download a bundle.\n *\n * Only available on Android and iOS.\n *\n * @since 5.0.0\n */\n downloadBundle(options: DownloadBundleOptions): Promise<void>;\n /**\n * Get the active bundle identifier.\n *\n * Only available on Android and iOS.\n *\n * @since 5.0.0\n */\n getBundle(): Promise<GetBundleResult>;\n /**\n * Get all available bundle identifiers.\n *\n * Only available on Android and iOS.\n *\n * @since 5.0.0\n */\n getBundles(): Promise<GetBundlesResult>;\n /**\n * Get the channel of the app.\n *\n * Only available on Android and iOS.\n *\n * @since 5.0.0\n */\n getChannel(): Promise<GetChannelResult>;\n /**\n * Get the custom identifier of the app.\n *\n * Only available on Android and iOS.\n *\n * @since 5.0.0\n */\n getCustomId(): Promise<GetCustomIdResult>;\n /**\n * Get the device identifier of the app.\n *\n * Only available on Android and iOS.\n *\n * @since 5.0.0\n */\n getDeviceId(): Promise<GetDeviceIdResult>;\n /**\n * Get the version code of the app.\n *\n * Only available on Android and iOS.\n *\n * @since 5.0.0\n */\n getVersionCode(): Promise<GetVersionCodeResult>;\n /**\n * Get the version name of the app.\n *\n * Only available on Android and iOS.\n *\n * @since 5.0.0\n */\n getVersionName(): Promise<GetVersionNameResult>;\n /**\n * Notify the plugin that the app is ready to use and no rollback is needed.\n *\n * Only available on Android and iOS.\n *\n * @since 5.0.0\n */\n ready(): Promise<void>;\n /**\n * Reload the app to apply the new bundle.\n *\n * Only available on Android and iOS.\n *\n * @since 5.0.0\n */\n reload(): Promise<void>;\n /**\n * Reset the app to the default bundle.\n *\n * Call `reload()` or restart the app to apply the changes.\n *\n * Only available on Android and iOS.\n *\n * @since 5.0.0\n */\n reset(): Promise<void>;\n /**\n * Set the next bundle to use for the app.\n *\n * Call `reload()` or restart the app to apply the changes.\n *\n * Only available on Android and iOS.\n *\n * @since 5.0.0\n */\n setBundle(options: SetBundleOptions): Promise<void>;\n /**\n * Set the channel of the app.\n *\n * Only available on Android and iOS.\n *\n * @since 5.0.0\n */\n setChannel(options: SetChannelOptions): Promise<void>;\n /**\n * Set the custom identifier of the app.\n *\n * Only available on Android and iOS.\n *\n * @since 5.0.0\n */\n setCustomId(options: SetCustomIdOptions): Promise<void>;\n /**\n * Automatically download and set the latest bundle for the app using the [Capawesome Cloud](https://capawesome.io/cloud/).\n *\n * Call `reload()` or restart the app to apply the changes.\n *\n * Only available on Android and iOS.\n *\n * @since 5.0.0\n */\n sync(): Promise<SyncResult>;\n}\n\n/**\n * @since 5.0.0\n */\nexport interface DeleteBundleOptions {\n /**\n * The unique identifier of the bundle to delete.\n *\n * @since 5.0.0\n * @example '1.0.0'\n */\n bundleId: string;\n}\n\nexport interface DownloadBundleOptions {\n /**\n * The URL of the bundle to download.\n *\n * The bundle must be a ZIP file containing at least a `index.html` file.\n *\n * @since 5.0.0\n * @example 'https://example.com/bundle.zip'\n */\n url: string;\n /**\n * The unique identifier of the bundle.\n *\n * @since 5.0.0\n * @example '1.0.0'\n */\n bundleId: string;\n}\n\n/**\n * @since 5.0.0\n */\nexport interface GetBundleResult {\n /**\n * The unique identifier of the active bundle.\n *\n * If `null`, the default bundle is being used.\n *\n * @since 5.0.0\n * @example '1.0.0'\n */\n bundleId: string | null;\n}\n\n/**\n * @since 5.0.0\n */\nexport interface GetBundlesResult {\n /**\n * An array of unique identifiers of all available bundles.\n *\n * @since 5.0.0\n */\n bundleIds: string[];\n}\n\n/**\n * @since 5.0.0\n */\nexport interface GetChannelResult {\n /**\n * The channel of the app.\n *\n * If `null`, the app is using the default channel.\n *\n * @since 5.0.0\n * @example 'production'\n */\n channel: string | null;\n}\n\n/**\n * @since 5.0.0\n */\nexport interface GetDeviceIdResult {\n /**\n * The unique identifier of the device.\n *\n * On iOS, [`identifierForVendor`](https://developer.apple.com/documentation/uikit/uidevice/1620059-identifierforvendor) is used.\n * The value of this property is the same for apps that come from the same vendor running on the same device.\n *\n * @since 5.0.0\n *\n * @example '50d2a548-80b7-4dad-adc7-97c0e79d8a89'\n */\n deviceId: string;\n}\n\n/**\n * @since 5.0.0\n */\nexport interface GetVersionCodeResult {\n /**\n * The version code of the app.\n *\n * On **Android**, this is the `versionCode` from the `android/app/build.gradle` file.\n * On **iOS**, this is the `CFBundleVersion` from the `Info.plist` file.\n *\n * @since 5.0.0\n * @example \"1\"\n */\n versionCode: string;\n}\n\n/**\n * @since 5.0.0\n */\nexport interface GetVersionNameResult {\n /**\n * The version name of the app.\n *\n * On **Android**, this is the `versionName` from the `android/app/build.gradle` file.\n * On **iOS**, this is the `CFBundleShortVersionString` from the `Info.plist` file.\n *\n * @since 5.0.0\n * @example \"1.0.0\"\n */\n versionName: string;\n}\n\n/**\n * @since 5.0.0\n */\nexport interface GetCustomIdResult {\n /**\n * The custom identifier of the app.\n *\n * If `null`, no custom identifier is set.\n *\n * @since 5.0.0\n * @example '50d2a548-80b7-4dad-adc7-97c0e79d8a89'\n */\n customId: string | null;\n}\n\n/**\n * @since 5.0.0\n */\nexport interface SetBundleOptions {\n /**\n * The unique identifier of the bundle to use.\n *\n * @since 5.0.0\n * @example '1.0.0'\n */\n bundleId: string;\n}\n\n/**\n * @since 5.0.0\n */\nexport interface SetChannelOptions {\n /**\n * The channel of the app.\n *\n * Set `null` to remove the channel.\n *\n * @since 5.0.0\n */\n channel: string | null;\n}\n\n/**\n * @since 5.0.0\n */\nexport interface SetCustomIdOptions {\n /**\n * The custom identifier of the app.\n *\n * Set `null` to remove the custom identifier.\n *\n * @since 5.0.0\n */\n customId: string | null;\n}\n\n/**\n * @since 5.0.0\n */\nexport interface SyncResult {\n /**\n * The identifier of the next bundle to use.\n *\n * If `null`, the app is up-to-date and no new bundle is available.\n *\n * @since 5.0.0\n */\n nextBundleId: string | null;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"AAAA,wCAAwC","sourcesContent":["/// <reference types=\"@capacitor/cli\" />\n\ndeclare module '@capacitor/cli' {\n export interface PluginsConfig {\n LiveUpdate?: {\n /**\n * The app ID is used to identify the app when using [Capawesome Cloud](https://capawesome.io/cloud).\n *\n * @since 5.0.0\n * @example '4100e356-e851-47fe-9d3c-b411eb325a99'\n */\n appId?: string;\n /**\n * Whether or not to automatically delete unused bundles.\n *\n * When enabled, the plugin will automatically delete unused bundles after calling `ready()`.\n *\n * @since 5.0.0\n * @default false\n */\n autoDeleteBundles?: boolean;\n /**\n * Whether or not the plugin is enabled.\n *\n * @since 5.0.0\n * @default true\n */\n enabled?: boolean;\n /**\n * The timeout in milliseconds to wait for the app to be ready before resetting to the default bundle.\n *\n * @since 5.0.0\n * @default 10000\n */\n readyTimeout?: number;\n /**\n * Whether or not the app should be reset to the default bundle during an update.\n *\n * @since 5.0.0\n * @default true\n */\n resetOnUpdate?: boolean;\n };\n }\n}\n\nexport interface LiveUpdatePlugin {\n /**\n * Delete a bundle from the app.\n *\n * Only available on Android and iOS.\n *\n * @since 5.0.0\n */\n deleteBundle(options: DeleteBundleOptions): Promise<void>;\n /**\n * Download a bundle.\n *\n * Only available on Android and iOS.\n *\n * @since 5.0.0\n */\n downloadBundle(options: DownloadBundleOptions): Promise<void>;\n /**\n * Get the active bundle identifier.\n *\n * Only available on Android and iOS.\n *\n * @since 5.0.0\n */\n getBundle(): Promise<GetBundleResult>;\n /**\n * Get all available bundle identifiers.\n *\n * Only available on Android and iOS.\n *\n * @since 5.0.0\n */\n getBundles(): Promise<GetBundlesResult>;\n /**\n * Get the channel of the app.\n *\n * Only available on Android and iOS.\n *\n * @since 5.0.0\n */\n getChannel(): Promise<GetChannelResult>;\n /**\n * Get the custom identifier of the app.\n *\n * Only available on Android and iOS.\n *\n * @since 5.0.0\n */\n getCustomId(): Promise<GetCustomIdResult>;\n /**\n * Get the device identifier of the app.\n *\n * Only available on Android and iOS.\n *\n * @since 5.0.0\n */\n getDeviceId(): Promise<GetDeviceIdResult>;\n /**\n * Get the version code of the app.\n *\n * Only available on Android and iOS.\n *\n * @since 5.0.0\n */\n getVersionCode(): Promise<GetVersionCodeResult>;\n /**\n * Get the version name of the app.\n *\n * Only available on Android and iOS.\n *\n * @since 5.0.0\n */\n getVersionName(): Promise<GetVersionNameResult>;\n /**\n * Notify the plugin that the app is ready to use and no rollback is needed.\n *\n * **Attention**: This method should be called as soon as the app is ready to use\n * to prevent the app from being reset to the default bundle.\n *\n * Only available on Android and iOS.\n *\n * @since 5.0.0\n */\n ready(): Promise<void>;\n /**\n * Reload the app to apply the new bundle.\n *\n * Only available on Android and iOS.\n *\n * @since 5.0.0\n */\n reload(): Promise<void>;\n /**\n * Reset the app to the default bundle.\n *\n * Call `reload()` or restart the app to apply the changes.\n *\n * Only available on Android and iOS.\n *\n * @since 5.0.0\n */\n reset(): Promise<void>;\n /**\n * Set the next bundle to use for the app.\n *\n * Call `reload()` or restart the app to apply the changes.\n *\n * Only available on Android and iOS.\n *\n * @since 5.0.0\n */\n setBundle(options: SetBundleOptions): Promise<void>;\n /**\n * Set the channel of the app.\n *\n * Only available on Android and iOS.\n *\n * @since 5.0.0\n */\n setChannel(options: SetChannelOptions): Promise<void>;\n /**\n * Set the custom identifier of the app.\n *\n * Only available on Android and iOS.\n *\n * @since 5.0.0\n */\n setCustomId(options: SetCustomIdOptions): Promise<void>;\n /**\n * Automatically download and set the latest bundle for the app using the [Capawesome Cloud](https://capawesome.io/cloud/).\n *\n * Call `reload()` or restart the app to apply the changes.\n *\n * Only available on Android and iOS.\n *\n * @since 5.0.0\n */\n sync(): Promise<SyncResult>;\n}\n\n/**\n * @since 5.0.0\n */\nexport interface DeleteBundleOptions {\n /**\n * The unique identifier of the bundle to delete.\n *\n * @since 5.0.0\n * @example '1.0.0'\n */\n bundleId: string;\n}\n\nexport interface DownloadBundleOptions {\n /**\n * The URL of the bundle to download.\n *\n * The bundle must be a ZIP file containing at least a `index.html` file.\n *\n * @since 5.0.0\n * @example 'https://example.com/bundle.zip'\n */\n url: string;\n /**\n * The unique identifier of the bundle.\n *\n * @since 5.0.0\n * @example '1.0.0'\n */\n bundleId: string;\n}\n\n/**\n * @since 5.0.0\n */\nexport interface GetBundleResult {\n /**\n * The unique identifier of the active bundle.\n *\n * If `null`, the default bundle is being used.\n *\n * @since 5.0.0\n * @example '1.0.0'\n */\n bundleId: string | null;\n}\n\n/**\n * @since 5.0.0\n */\nexport interface GetBundlesResult {\n /**\n * An array of unique identifiers of all available bundles.\n *\n * @since 5.0.0\n */\n bundleIds: string[];\n}\n\n/**\n * @since 5.0.0\n */\nexport interface GetChannelResult {\n /**\n * The channel of the app.\n *\n * If `null`, the app is using the default channel.\n *\n * @since 5.0.0\n * @example 'production'\n */\n channel: string | null;\n}\n\n/**\n * @since 5.0.0\n */\nexport interface GetDeviceIdResult {\n /**\n * The unique identifier of the device.\n *\n * On iOS, [`identifierForVendor`](https://developer.apple.com/documentation/uikit/uidevice/1620059-identifierforvendor) is used.\n * The value of this property is the same for apps that come from the same vendor running on the same device.\n *\n * @since 5.0.0\n *\n * @example '50d2a548-80b7-4dad-adc7-97c0e79d8a89'\n */\n deviceId: string;\n}\n\n/**\n * @since 5.0.0\n */\nexport interface GetVersionCodeResult {\n /**\n * The version code of the app.\n *\n * On **Android**, this is the `versionCode` from the `android/app/build.gradle` file.\n * On **iOS**, this is the `CFBundleVersion` from the `Info.plist` file.\n *\n * @since 5.0.0\n * @example \"1\"\n */\n versionCode: string;\n}\n\n/**\n * @since 5.0.0\n */\nexport interface GetVersionNameResult {\n /**\n * The version name of the app.\n *\n * On **Android**, this is the `versionName` from the `android/app/build.gradle` file.\n * On **iOS**, this is the `CFBundleShortVersionString` from the `Info.plist` file.\n *\n * @since 5.0.0\n * @example \"1.0.0\"\n */\n versionName: string;\n}\n\n/**\n * @since 5.0.0\n */\nexport interface GetCustomIdResult {\n /**\n * The custom identifier of the app.\n *\n * If `null`, no custom identifier is set.\n *\n * @since 5.0.0\n * @example '50d2a548-80b7-4dad-adc7-97c0e79d8a89'\n */\n customId: string | null;\n}\n\n/**\n * @since 5.0.0\n */\nexport interface SetBundleOptions {\n /**\n * The unique identifier of the bundle to use.\n *\n * @since 5.0.0\n * @example '1.0.0'\n */\n bundleId: string;\n}\n\n/**\n * @since 5.0.0\n */\nexport interface SetChannelOptions {\n /**\n * The channel of the app.\n *\n * Set `null` to remove the channel.\n *\n * @since 5.0.0\n */\n channel: string | null;\n}\n\n/**\n * @since 5.0.0\n */\nexport interface SetCustomIdOptions {\n /**\n * The custom identifier of the app.\n *\n * Set `null` to remove the custom identifier.\n *\n * @since 5.0.0\n */\n customId: string | null;\n}\n\n/**\n * @since 5.0.0\n */\nexport interface SyncResult {\n /**\n * The identifier of the next bundle to use.\n *\n * If `null`, the app is up-to-date and no new bundle is available.\n *\n * @since 5.0.0\n */\n nextBundleId: string | null;\n}\n"]}
|
|
@@ -21,7 +21,6 @@ import Alamofire
|
|
|
21
21
|
self.plugin = plugin
|
|
22
22
|
self.preferences = LiveUpdatePreferences()
|
|
23
23
|
super.init()
|
|
24
|
-
createBundlesDirectory()
|
|
25
24
|
|
|
26
25
|
if config.enabled {
|
|
27
26
|
if wasUpdated() && config.resetOnUpdate {
|
|
@@ -126,17 +125,9 @@ import Alamofire
|
|
|
126
125
|
}
|
|
127
126
|
|
|
128
127
|
@objc public func reload() {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
}
|
|
133
|
-
if let nextPath = getNextCapacitorServerPath() {
|
|
134
|
-
path = nextPath
|
|
135
|
-
}
|
|
136
|
-
if let path = path {
|
|
137
|
-
setCurrentCapacitorServerPath(path: path)
|
|
138
|
-
startRollbackTimer()
|
|
139
|
-
}
|
|
128
|
+
let path = getNextCapacitorServerPath()
|
|
129
|
+
setCurrentCapacitorServerPath(path: path)
|
|
130
|
+
startRollbackTimer()
|
|
140
131
|
}
|
|
141
132
|
|
|
142
133
|
@objc public func reset() {
|
|
@@ -219,6 +210,10 @@ import Alamofire
|
|
|
219
210
|
completion(CustomError.bundleIndexHtmlMissing)
|
|
220
211
|
return
|
|
221
212
|
}
|
|
213
|
+
|
|
214
|
+
// Create the bundles directory if it does not exist
|
|
215
|
+
self.createBundlesDirectory()
|
|
216
|
+
|
|
222
217
|
// Move the unzipped files to the bundles directory
|
|
223
218
|
let bundlePath = self.buildBundlePathFor(bundleId: bundleId)
|
|
224
219
|
do {
|
|
@@ -335,8 +330,12 @@ import Alamofire
|
|
|
335
330
|
parameters["pluginVersion"] = LiveUpdatePlugin.version
|
|
336
331
|
let url = URL(string: "https://api.cloud.capawesome.io/v1/apps/\(config.appId ?? "")/bundles/latest")!
|
|
337
332
|
AF.request(url, method: .get, parameters: parameters).validate().responseDecodable(of: GetLatestBundleResponse.self) { response in
|
|
333
|
+
CAPLog.print("[", LiveUpdatePlugin.tag, "] Fetching latest bundle from ", response.request?.url?.absoluteString ?? "")
|
|
338
334
|
if let error = response.error {
|
|
339
335
|
CAPLog.print("[", LiveUpdatePlugin.tag, "] ", error)
|
|
336
|
+
if let data = response.data {
|
|
337
|
+
CAPLog.print("[", LiveUpdatePlugin.tag, "] ", String(decoding: data, as: UTF8.self))
|
|
338
|
+
}
|
|
340
339
|
completion(nil, error)
|
|
341
340
|
return
|
|
342
341
|
}
|
|
@@ -372,6 +371,7 @@ import Alamofire
|
|
|
372
371
|
}
|
|
373
372
|
}
|
|
374
373
|
|
|
374
|
+
/// - Returns: The current bundle ID (`public` for the built-in bundle) or `nil` if no view controller was found.
|
|
375
375
|
private func getCurrentBundleId() -> String? {
|
|
376
376
|
guard let path = getCurrentCapacitorServerPath() else {
|
|
377
377
|
return nil
|
|
@@ -379,6 +379,7 @@ import Alamofire
|
|
|
379
379
|
return URL(fileURLWithPath: path).lastPathComponent
|
|
380
380
|
}
|
|
381
381
|
|
|
382
|
+
/// - Returns: The path to the current bundle directory or `nil` if no view controller was found.
|
|
382
383
|
private func getCurrentCapacitorServerPath() -> String? {
|
|
383
384
|
guard let viewController = self.plugin.bridge?.viewController as? CAPBridgeViewController else {
|
|
384
385
|
return nil
|
|
@@ -391,18 +392,19 @@ import Alamofire
|
|
|
391
392
|
return deviceId.lowercased()
|
|
392
393
|
}
|
|
393
394
|
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
}
|
|
395
|
+
/// - Returns: The next bundle ID (`public` for the built-in bundle).
|
|
396
|
+
private func getNextBundleId() -> String {
|
|
397
|
+
let path = getNextCapacitorServerPath()
|
|
398
398
|
return URL(fileURLWithPath: path).lastPathComponent
|
|
399
399
|
}
|
|
400
400
|
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
401
|
+
/// - Returns: The absolute path to the next bundle directory.
|
|
402
|
+
private func getNextCapacitorServerPath() -> String {
|
|
403
|
+
let defaultCapacitorServerPath = buildCapacitorServerPathFor(bundleId: defaultWebAssetDir)
|
|
404
|
+
if let path = KeyValueStore.standard[self.defaultServerPathKey, as: String.self] {
|
|
405
|
+
return path.isEmpty ? defaultCapacitorServerPath : path
|
|
404
406
|
}
|
|
405
|
-
return
|
|
407
|
+
return defaultCapacitorServerPath
|
|
406
408
|
}
|
|
407
409
|
|
|
408
410
|
private func hasBundle(bundleId: String) -> Bool {
|
|
@@ -456,13 +458,12 @@ import Alamofire
|
|
|
456
458
|
|
|
457
459
|
private func setNextCapacitorServerPath(path: String) {
|
|
458
460
|
if path.hasSuffix("/public") {
|
|
459
|
-
//
|
|
460
|
-
|
|
461
|
+
// Must set an empty string to reset the custom server base path
|
|
462
|
+
KeyValueStore.standard[self.defaultServerPathKey] = ""
|
|
461
463
|
} else {
|
|
462
464
|
// Attention: Only the lastPathComponent is used (see https://dub.sh/BLluidt)
|
|
463
|
-
|
|
465
|
+
KeyValueStore.standard[self.defaultServerPathKey] = path
|
|
464
466
|
}
|
|
465
|
-
UserDefaults.standard.synchronize()
|
|
466
467
|
}
|
|
467
468
|
|
|
468
469
|
private func setNextCapacitorServerPathToDefaultWebAssetDir() {
|
|
@@ -8,7 +8,7 @@ import Capacitor
|
|
|
8
8
|
@objc(LiveUpdatePlugin)
|
|
9
9
|
public class LiveUpdatePlugin: CAPPlugin {
|
|
10
10
|
public static let tag = "LiveUpdate"
|
|
11
|
-
public static let version = "6.0.
|
|
11
|
+
public static let version = "6.0.7"
|
|
12
12
|
public static let userDefaultsPrefix = "CapawesomeLiveUpdate" // DO NOT CHANGE
|
|
13
13
|
|
|
14
14
|
private var config: LiveUpdateConfig?
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@capawesome/capacitor-live-update",
|
|
3
|
-
"version": "6.0.
|
|
3
|
+
"version": "6.0.8",
|
|
4
4
|
"description": "Capacitor plugin to update your app remotely in real-time.",
|
|
5
5
|
"main": "dist/plugin.cjs.js",
|
|
6
6
|
"module": "dist/esm/index.js",
|
|
@@ -36,7 +36,14 @@
|
|
|
36
36
|
"keywords": [
|
|
37
37
|
"capacitor",
|
|
38
38
|
"plugin",
|
|
39
|
-
"native"
|
|
39
|
+
"native",
|
|
40
|
+
"ionic",
|
|
41
|
+
"android",
|
|
42
|
+
"ios",
|
|
43
|
+
"live update",
|
|
44
|
+
"remote update",
|
|
45
|
+
"ota",
|
|
46
|
+
"capgo"
|
|
40
47
|
],
|
|
41
48
|
"scripts": {
|
|
42
49
|
"verify": "npm run verify:ios && npm run verify:android && npm run verify:web",
|