@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 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 currentPath = getCurrentCapacitorServerPath();
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
- @Nullable
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, null);
523
+ .getString(WebView.CAP_SERVER_PATH, defaultWebAssetDir);
514
524
  }
515
525
 
516
526
  private boolean hasBundle(@NonNull String bundleId) {
@@ -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.6";
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
- var path: String?
130
- if let currentPath = getCurrentCapacitorServerPath() {
131
- path = currentPath
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
- private func getNextBundleId() -> String? {
395
- guard let path = getNextCapacitorServerPath() else {
396
- return nil
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
- private func getNextCapacitorServerPath() -> String? {
402
- if let path = UserDefaults.standard.string(forKey: self.defaultServerPathKey) {
403
- return path.isEmpty ? nil : path
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 nil
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
- // Reset the custom server base path
460
- UserDefaults.standard.set("", forKey: self.defaultServerPathKey)
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
- UserDefaults.standard.set(path, forKey: self.defaultServerPathKey)
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.6"
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.6",
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",