native-update 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (184) hide show
  1. package/CapacitorNativeUpdate.podspec +18 -0
  2. package/LICENSE +21 -0
  3. package/Readme.md +451 -0
  4. package/android/build.gradle +92 -0
  5. package/android/gradle/wrapper/gradle-wrapper.properties +8 -0
  6. package/android/gradle.properties +17 -0
  7. package/android/proguard-rules.pro +29 -0
  8. package/android/settings.gradle +2 -0
  9. package/android/src/main/AndroidManifest.xml +34 -0
  10. package/android/src/main/java/com/aoneahsan/nativeupdate/AppReviewPlugin.kt +153 -0
  11. package/android/src/main/java/com/aoneahsan/nativeupdate/AppUpdatePlugin.kt +275 -0
  12. package/android/src/main/java/com/aoneahsan/nativeupdate/BackgroundNotificationManager.kt +390 -0
  13. package/android/src/main/java/com/aoneahsan/nativeupdate/BackgroundUpdateManager.kt +46 -0
  14. package/android/src/main/java/com/aoneahsan/nativeupdate/BackgroundUpdatePlugin.kt +333 -0
  15. package/android/src/main/java/com/aoneahsan/nativeupdate/BackgroundUpdateWorker.kt +251 -0
  16. package/android/src/main/java/com/aoneahsan/nativeupdate/CapacitorNativeUpdatePlugin.kt +265 -0
  17. package/android/src/main/java/com/aoneahsan/nativeupdate/LiveUpdatePlugin.kt +526 -0
  18. package/android/src/main/java/com/aoneahsan/nativeupdate/NotificationActionReceiver.kt +99 -0
  19. package/android/src/main/java/com/aoneahsan/nativeupdate/SecurityManager.kt +249 -0
  20. package/dist/esm/__tests__/bundle-manager.test.d.ts +1 -0
  21. package/dist/esm/__tests__/bundle-manager.test.js +123 -0
  22. package/dist/esm/__tests__/bundle-manager.test.js.map +1 -0
  23. package/dist/esm/__tests__/config.test.d.ts +1 -0
  24. package/dist/esm/__tests__/config.test.js +69 -0
  25. package/dist/esm/__tests__/config.test.js.map +1 -0
  26. package/dist/esm/__tests__/integration.test.d.ts +1 -0
  27. package/dist/esm/__tests__/integration.test.js +78 -0
  28. package/dist/esm/__tests__/integration.test.js.map +1 -0
  29. package/dist/esm/__tests__/security.test.d.ts +1 -0
  30. package/dist/esm/__tests__/security.test.js +54 -0
  31. package/dist/esm/__tests__/security.test.js.map +1 -0
  32. package/dist/esm/__tests__/version-manager.test.d.ts +1 -0
  33. package/dist/esm/__tests__/version-manager.test.js +45 -0
  34. package/dist/esm/__tests__/version-manager.test.js.map +1 -0
  35. package/dist/esm/app-review/app-review-manager.d.ts +24 -0
  36. package/dist/esm/app-review/app-review-manager.js +195 -0
  37. package/dist/esm/app-review/app-review-manager.js.map +1 -0
  38. package/dist/esm/app-review/index.d.ts +5 -0
  39. package/dist/esm/app-review/index.js +6 -0
  40. package/dist/esm/app-review/index.js.map +1 -0
  41. package/dist/esm/app-review/platform-review-handler.d.ts +20 -0
  42. package/dist/esm/app-review/platform-review-handler.js +138 -0
  43. package/dist/esm/app-review/platform-review-handler.js.map +1 -0
  44. package/dist/esm/app-review/review-conditions-checker.d.ts +22 -0
  45. package/dist/esm/app-review/review-conditions-checker.js +155 -0
  46. package/dist/esm/app-review/review-conditions-checker.js.map +1 -0
  47. package/dist/esm/app-review/review-rate-limiter.d.ts +23 -0
  48. package/dist/esm/app-review/review-rate-limiter.js +164 -0
  49. package/dist/esm/app-review/review-rate-limiter.js.map +1 -0
  50. package/dist/esm/app-review/types.d.ts +41 -0
  51. package/dist/esm/app-review/types.js +2 -0
  52. package/dist/esm/app-review/types.js.map +1 -0
  53. package/dist/esm/app-update/app-update-checker.d.ts +13 -0
  54. package/dist/esm/app-update/app-update-checker.js +104 -0
  55. package/dist/esm/app-update/app-update-checker.js.map +1 -0
  56. package/dist/esm/app-update/app-update-installer.d.ts +19 -0
  57. package/dist/esm/app-update/app-update-installer.js +123 -0
  58. package/dist/esm/app-update/app-update-installer.js.map +1 -0
  59. package/dist/esm/app-update/app-update-manager.d.ts +28 -0
  60. package/dist/esm/app-update/app-update-manager.js +199 -0
  61. package/dist/esm/app-update/app-update-manager.js.map +1 -0
  62. package/dist/esm/app-update/app-update-notifier.d.ts +14 -0
  63. package/dist/esm/app-update/app-update-notifier.js +100 -0
  64. package/dist/esm/app-update/app-update-notifier.js.map +1 -0
  65. package/dist/esm/app-update/index.d.ts +6 -0
  66. package/dist/esm/app-update/index.js +7 -0
  67. package/dist/esm/app-update/index.js.map +1 -0
  68. package/dist/esm/app-update/platform-app-update.d.ts +19 -0
  69. package/dist/esm/app-update/platform-app-update.js +129 -0
  70. package/dist/esm/app-update/platform-app-update.js.map +1 -0
  71. package/dist/esm/app-update/types.d.ts +58 -0
  72. package/dist/esm/app-update/types.js +12 -0
  73. package/dist/esm/app-update/types.js.map +1 -0
  74. package/dist/esm/background-update/background-scheduler.d.ts +17 -0
  75. package/dist/esm/background-update/background-scheduler.js +195 -0
  76. package/dist/esm/background-update/background-scheduler.js.map +1 -0
  77. package/dist/esm/background-update/index.d.ts +3 -0
  78. package/dist/esm/background-update/index.js +3 -0
  79. package/dist/esm/background-update/index.js.map +1 -0
  80. package/dist/esm/background-update/notification-manager.d.ts +29 -0
  81. package/dist/esm/background-update/notification-manager.js +89 -0
  82. package/dist/esm/background-update/notification-manager.js.map +1 -0
  83. package/dist/esm/core/analytics.d.ts +70 -0
  84. package/dist/esm/core/analytics.js +137 -0
  85. package/dist/esm/core/analytics.js.map +1 -0
  86. package/dist/esm/core/cache-manager.d.ts +72 -0
  87. package/dist/esm/core/cache-manager.js +275 -0
  88. package/dist/esm/core/cache-manager.js.map +1 -0
  89. package/dist/esm/core/config.d.ts +48 -0
  90. package/dist/esm/core/config.js +83 -0
  91. package/dist/esm/core/config.js.map +1 -0
  92. package/dist/esm/core/errors.d.ts +51 -0
  93. package/dist/esm/core/errors.js +80 -0
  94. package/dist/esm/core/errors.js.map +1 -0
  95. package/dist/esm/core/logger.d.ts +21 -0
  96. package/dist/esm/core/logger.js +109 -0
  97. package/dist/esm/core/logger.js.map +1 -0
  98. package/dist/esm/core/performance.d.ts +53 -0
  99. package/dist/esm/core/performance.js +140 -0
  100. package/dist/esm/core/performance.js.map +1 -0
  101. package/dist/esm/core/plugin-manager.d.ts +66 -0
  102. package/dist/esm/core/plugin-manager.js +148 -0
  103. package/dist/esm/core/plugin-manager.js.map +1 -0
  104. package/dist/esm/core/security.d.ts +93 -0
  105. package/dist/esm/core/security.js +315 -0
  106. package/dist/esm/core/security.js.map +1 -0
  107. package/dist/esm/definitions.d.ts +639 -0
  108. package/dist/esm/definitions.js +103 -0
  109. package/dist/esm/definitions.js.map +1 -0
  110. package/dist/esm/index.d.ts +12 -0
  111. package/dist/esm/index.js +16 -0
  112. package/dist/esm/index.js.map +1 -0
  113. package/dist/esm/live-update/bundle-manager.d.ts +94 -0
  114. package/dist/esm/live-update/bundle-manager.js +310 -0
  115. package/dist/esm/live-update/bundle-manager.js.map +1 -0
  116. package/dist/esm/live-update/certificate-pinning.d.ts +38 -0
  117. package/dist/esm/live-update/certificate-pinning.js +78 -0
  118. package/dist/esm/live-update/certificate-pinning.js.map +1 -0
  119. package/dist/esm/live-update/download-manager.d.ts +67 -0
  120. package/dist/esm/live-update/download-manager.js +319 -0
  121. package/dist/esm/live-update/download-manager.js.map +1 -0
  122. package/dist/esm/live-update/update-manager.d.ts +52 -0
  123. package/dist/esm/live-update/update-manager.js +294 -0
  124. package/dist/esm/live-update/update-manager.js.map +1 -0
  125. package/dist/esm/live-update/version-manager.d.ts +84 -0
  126. package/dist/esm/live-update/version-manager.js +335 -0
  127. package/dist/esm/live-update/version-manager.js.map +1 -0
  128. package/dist/esm/plugin.d.ts +6 -0
  129. package/dist/esm/plugin.js +283 -0
  130. package/dist/esm/plugin.js.map +1 -0
  131. package/dist/esm/security/crypto.d.ts +25 -0
  132. package/dist/esm/security/crypto.js +70 -0
  133. package/dist/esm/security/crypto.js.map +1 -0
  134. package/dist/esm/security/validator.d.ts +60 -0
  135. package/dist/esm/security/validator.js +143 -0
  136. package/dist/esm/security/validator.js.map +1 -0
  137. package/dist/esm/web.d.ts +74 -0
  138. package/dist/esm/web.js +595 -0
  139. package/dist/esm/web.js.map +1 -0
  140. package/dist/plugin.cjs.js +2 -0
  141. package/dist/plugin.cjs.js.map +1 -0
  142. package/dist/plugin.esm.js +2 -0
  143. package/dist/plugin.esm.js.map +1 -0
  144. package/dist/plugin.js +3 -0
  145. package/dist/plugin.js.map +1 -0
  146. package/docs/APP_REVIEW_GUIDE.md +768 -0
  147. package/docs/BUNDLE_SIGNING.md +264 -0
  148. package/docs/LIVE_UPDATES_GUIDE.md +650 -0
  149. package/docs/MIGRATION.md +192 -0
  150. package/docs/NATIVE_UPDATES_GUIDE.md +694 -0
  151. package/docs/QUICK_START.md +606 -0
  152. package/docs/README.md +111 -0
  153. package/docs/REMAINING_FEATURES.md +139 -0
  154. package/docs/api/app-review-api.md +259 -0
  155. package/docs/api/app-update-api.md +238 -0
  156. package/docs/api/events-api.md +451 -0
  157. package/docs/api/live-update-api.md +265 -0
  158. package/docs/background-updates.md +392 -0
  159. package/docs/examples/advanced-scenarios.md +410 -0
  160. package/docs/examples/basic-usage.md +185 -0
  161. package/docs/features/app-reviews.md +975 -0
  162. package/docs/features/app-updates.md +785 -0
  163. package/docs/features/live-updates.md +633 -0
  164. package/docs/getting-started/configuration.md +468 -0
  165. package/docs/getting-started/installation.md +209 -0
  166. package/docs/getting-started/quick-start.md +379 -0
  167. package/docs/guides/deployment-guide.md +333 -0
  168. package/docs/guides/migration-from-codepush.md +142 -0
  169. package/docs/guides/security-best-practices.md +1057 -0
  170. package/docs/guides/testing-guide.md +373 -0
  171. package/docs/production-readiness.md +478 -0
  172. package/docs/security/certificate-pinning.md +122 -0
  173. package/docs/server-requirements.md +147 -0
  174. package/ios/Plugin/AppReview/AppReviewPlugin.swift +158 -0
  175. package/ios/Plugin/AppUpdate/AppUpdatePlugin.swift +234 -0
  176. package/ios/Plugin/BackgroundUpdate/BackgroundNotificationManager.swift +329 -0
  177. package/ios/Plugin/BackgroundUpdate/BackgroundUpdatePlugin.swift +396 -0
  178. package/ios/Plugin/CapacitorNativeUpdatePlugin.m +45 -0
  179. package/ios/Plugin/CapacitorNativeUpdatePlugin.swift +190 -0
  180. package/ios/Plugin/Info.plist +43 -0
  181. package/ios/Plugin/LiveUpdate/LiveUpdatePlugin.swift +689 -0
  182. package/ios/Plugin/LiveUpdate/WebViewConfiguration.swift +45 -0
  183. package/ios/Plugin/Security/SecurityManager.swift +289 -0
  184. package/package.json +90 -0
@@ -0,0 +1,785 @@
1
+ # App Updates
2
+
3
+ The App Updates feature provides a seamless way to manage native app store updates, ensuring users always have the latest version of your app with critical native changes, new permissions, or platform-specific features.
4
+
5
+ ## Overview
6
+
7
+ While Live Updates handle web assets, App Updates manage the native app binary itself. This feature integrates with:
8
+
9
+ - **Google Play Store** on Android (using Play Core Library)
10
+ - **Apple App Store** on iOS (using manual version checking)
11
+ - **Web platforms** with fallback notifications
12
+
13
+ ## Key Features
14
+
15
+ ### 🎯 Update Priority Management
16
+
17
+ - Configure update urgency (0-5 scale)
18
+ - Force critical updates
19
+ - Flexible update scheduling
20
+
21
+ ### 📱 Native UI Integration
22
+
23
+ - Platform-specific update dialogs
24
+ - In-app download progress
25
+ - Seamless installation flow
26
+
27
+ ### 🔄 Update Types
28
+
29
+ - **Immediate Updates**: Blocking updates for critical fixes
30
+ - **Flexible Updates**: Background downloads with user control
31
+ - **Manual Updates**: Direct app store navigation
32
+
33
+ ### 📊 Version Intelligence
34
+
35
+ - Semantic version comparison
36
+ - Minimum version enforcement
37
+ - Update availability detection
38
+
39
+ ## Implementation Guide
40
+
41
+ ### Basic Implementation
42
+
43
+ ```typescript
44
+ // Check for app updates on startup
45
+ async function checkForAppUpdates() {
46
+ try {
47
+ const updateInfo = await CapacitorNativeUpdate.AppUpdate.getAppUpdateInfo();
48
+
49
+ if (updateInfo.updateAvailable) {
50
+ console.log(`Update available: ${updateInfo.availableVersion}`);
51
+
52
+ // Handle based on priority
53
+ if (updateInfo.updatePriority >= 4) {
54
+ // High priority - immediate update
55
+ await CapacitorNativeUpdate.AppUpdate.performImmediateUpdate();
56
+ } else {
57
+ // Optional update - show custom UI
58
+ showUpdateDialog(updateInfo);
59
+ }
60
+ }
61
+ } catch (error) {
62
+ console.error('Update check failed:', error);
63
+ }
64
+ }
65
+ ```
66
+
67
+ ### Advanced Implementation
68
+
69
+ ```typescript
70
+ class AppUpdateManager {
71
+ private updateInfo: AppUpdateInfo | null = null;
72
+ private downloadProgress = 0;
73
+
74
+ async initialize() {
75
+ // Configure app updates
76
+ await CapacitorNativeUpdate.configure({
77
+ appUpdate: {
78
+ checkOnAppStart: true,
79
+ minimumVersion: '2.0.0',
80
+ updatePriority: 3,
81
+ storeUrl: {
82
+ android: 'https://play.google.com/store/apps/details?id=com.myapp',
83
+ ios: 'https://apps.apple.com/app/id123456789',
84
+ },
85
+ },
86
+ });
87
+
88
+ // Set up listeners
89
+ this.setupUpdateListeners();
90
+
91
+ // Check for updates
92
+ await this.checkForUpdates();
93
+ }
94
+
95
+ private setupUpdateListeners() {
96
+ // Android flexible update state changes
97
+ CapacitorNativeUpdate.AppUpdate.addListener(
98
+ 'flexibleUpdateStateChanged',
99
+ (state) => {
100
+ this.handleFlexibleUpdateState(state);
101
+ }
102
+ );
103
+
104
+ // Download progress for flexible updates
105
+ CapacitorNativeUpdate.AppUpdate.addListener(
106
+ 'flexibleUpdateProgress',
107
+ (progress) => {
108
+ this.downloadProgress = progress.percent;
109
+ this.updateProgressUI(progress);
110
+ }
111
+ );
112
+ }
113
+
114
+ async checkForUpdates() {
115
+ try {
116
+ this.updateInfo =
117
+ await CapacitorNativeUpdate.AppUpdate.getAppUpdateInfo();
118
+
119
+ if (!this.updateInfo.updateAvailable) {
120
+ console.log('App is up to date');
121
+ return;
122
+ }
123
+
124
+ // Analyze update type needed
125
+ const updateType = this.determineUpdateType(this.updateInfo);
126
+
127
+ switch (updateType) {
128
+ case 'IMMEDIATE':
129
+ await this.performImmediateUpdate();
130
+ break;
131
+ case 'FLEXIBLE':
132
+ await this.startFlexibleUpdate();
133
+ break;
134
+ case 'OPTIONAL':
135
+ this.showOptionalUpdateUI();
136
+ break;
137
+ }
138
+ } catch (error) {
139
+ this.handleUpdateError(error);
140
+ }
141
+ }
142
+
143
+ private determineUpdateType(info: AppUpdateInfo): string {
144
+ // Force immediate update for critical priority
145
+ if (info.updatePriority === 5) {
146
+ return 'IMMEDIATE';
147
+ }
148
+
149
+ // Check if current version is below minimum
150
+ if (this.isVersionBelowMinimum(info.currentVersion, info.minimumVersion)) {
151
+ return 'IMMEDIATE';
152
+ }
153
+
154
+ // High priority gets flexible update
155
+ if (info.updatePriority >= 3) {
156
+ return 'FLEXIBLE';
157
+ }
158
+
159
+ // Low priority is optional
160
+ return 'OPTIONAL';
161
+ }
162
+
163
+ async performImmediateUpdate() {
164
+ try {
165
+ // Show blocking update UI
166
+ this.showImmediateUpdateUI();
167
+
168
+ // Start immediate update
169
+ await CapacitorNativeUpdate.AppUpdate.performImmediateUpdate();
170
+
171
+ // App will restart automatically after update
172
+ } catch (error) {
173
+ if (error.code === 'UPDATE_CANCELLED') {
174
+ // User cancelled - handle based on requirements
175
+ if (this.updateInfo?.updatePriority === 5) {
176
+ // Critical update - exit app
177
+ App.exitApp();
178
+ }
179
+ }
180
+ }
181
+ }
182
+
183
+ async startFlexibleUpdate() {
184
+ try {
185
+ // Start background download
186
+ await CapacitorNativeUpdate.AppUpdate.startFlexibleUpdate();
187
+
188
+ // Show download progress UI
189
+ this.showFlexibleUpdateUI();
190
+ } catch (error) {
191
+ this.handleUpdateError(error);
192
+ }
193
+ }
194
+
195
+ private handleFlexibleUpdateState(state: FlexibleUpdateState) {
196
+ switch (state.status) {
197
+ case 'PENDING':
198
+ console.log('Update pending');
199
+ break;
200
+
201
+ case 'DOWNLOADING':
202
+ console.log('Downloading update...');
203
+ break;
204
+
205
+ case 'DOWNLOADED':
206
+ // Update ready to install
207
+ this.showInstallPrompt();
208
+ break;
209
+
210
+ case 'INSTALLING':
211
+ console.log('Installing update...');
212
+ break;
213
+
214
+ case 'INSTALLED':
215
+ console.log('Update installed successfully');
216
+ break;
217
+
218
+ case 'FAILED':
219
+ this.handleUpdateError(new Error(state.error));
220
+ break;
221
+ }
222
+ }
223
+
224
+ async completeFlexibleUpdate() {
225
+ try {
226
+ await CapacitorNativeUpdate.AppUpdate.completeFlexibleUpdate();
227
+ // App will restart with new version
228
+ } catch (error) {
229
+ console.error('Failed to complete update:', error);
230
+ }
231
+ }
232
+
233
+ private showInstallPrompt() {
234
+ // Show snackbar or dialog
235
+ this.showDialog({
236
+ title: 'Update Ready',
237
+ message: 'An update has been downloaded. Restart to apply?',
238
+ buttons: [
239
+ {
240
+ text: 'Restart',
241
+ handler: () => this.completeFlexibleUpdate(),
242
+ },
243
+ {
244
+ text: 'Later',
245
+ handler: () => {
246
+ // Schedule reminder
247
+ this.scheduleUpdateReminder();
248
+ },
249
+ },
250
+ ],
251
+ });
252
+ }
253
+ }
254
+ ```
255
+
256
+ ## Platform-Specific Behavior
257
+
258
+ ### Android (Google Play)
259
+
260
+ Android uses the Google Play Core Library for in-app updates:
261
+
262
+ ```typescript
263
+ // Android-specific features
264
+ const androidUpdate = {
265
+ // Immediate update flow
266
+ immediate: async () => {
267
+ // Blocks UI until update is installed
268
+ await CapacitorNativeUpdate.AppUpdate.performImmediateUpdate();
269
+ // App restarts automatically
270
+ },
271
+
272
+ // Flexible update flow
273
+ flexible: async () => {
274
+ // Download in background
275
+ await CapacitorNativeUpdate.AppUpdate.startFlexibleUpdate();
276
+
277
+ // Monitor progress
278
+ const listener = await CapacitorNativeUpdate.AppUpdate.addListener(
279
+ 'flexibleUpdateProgress',
280
+ (progress) => {
281
+ console.log(
282
+ `Downloaded: ${progress.bytesDownloaded}/${progress.totalBytes}`
283
+ );
284
+ }
285
+ );
286
+
287
+ // Complete when ready
288
+ await CapacitorNativeUpdate.AppUpdate.completeFlexibleUpdate();
289
+ },
290
+ };
291
+ ```
292
+
293
+ ### iOS (App Store)
294
+
295
+ iOS requires manual version checking and App Store redirection:
296
+
297
+ ```typescript
298
+ // iOS-specific implementation
299
+ const iosUpdate = {
300
+ // Check version manually
301
+ check: async () => {
302
+ const info = await CapacitorNativeUpdate.AppUpdate.getAppUpdateInfo();
303
+
304
+ if (info.updateAvailable) {
305
+ // Show custom update dialog
306
+ const shouldUpdate = await showUpdateDialog(info);
307
+
308
+ if (shouldUpdate) {
309
+ // Open App Store
310
+ await CapacitorNativeUpdate.AppUpdate.openAppStore();
311
+ }
312
+ }
313
+ },
314
+ };
315
+ ```
316
+
317
+ ### Web Platform
318
+
319
+ Web platforms show update notifications:
320
+
321
+ ```typescript
322
+ // Web fallback
323
+ const webUpdate = {
324
+ notify: async () => {
325
+ const info = await CapacitorNativeUpdate.AppUpdate.getAppUpdateInfo();
326
+
327
+ if (info.updateAvailable) {
328
+ // Show notification
329
+ new Notification('Update Available', {
330
+ body: `Version ${info.availableVersion} is available`,
331
+ icon: '/icon.png',
332
+ actions: [
333
+ {
334
+ action: 'update',
335
+ title: 'Update Now',
336
+ },
337
+ ],
338
+ });
339
+ }
340
+ },
341
+ };
342
+ ```
343
+
344
+ ## Update Priority Levels
345
+
346
+ Configure update behavior based on priority:
347
+
348
+ ```typescript
349
+ const updatePriorities = {
350
+ 0: {
351
+ // Low priority
352
+ name: 'Optional',
353
+ behavior: 'Show notification only',
354
+ userControl: 'full',
355
+ },
356
+ 1: {
357
+ // Minor improvements
358
+ name: 'Recommended',
359
+ behavior: 'Show dialog on app start',
360
+ userControl: 'dismissible',
361
+ },
362
+ 2: {
363
+ // Important features
364
+ name: 'Important',
365
+ behavior: 'Prompt after key actions',
366
+ userControl: 'postponable',
367
+ },
368
+ 3: {
369
+ // Significant changes
370
+ name: 'High',
371
+ behavior: 'Flexible update with reminders',
372
+ userControl: 'limited',
373
+ },
374
+ 4: {
375
+ // Critical fixes
376
+ name: 'Critical',
377
+ behavior: 'Immediate update prompt',
378
+ userControl: 'minimal',
379
+ },
380
+ 5: {
381
+ // Security updates
382
+ name: 'Mandatory',
383
+ behavior: 'Force immediate update',
384
+ userControl: 'none',
385
+ },
386
+ };
387
+ ```
388
+
389
+ ## Version Management
390
+
391
+ ### Semantic Version Comparison
392
+
393
+ ```typescript
394
+ class VersionManager {
395
+ // Compare semantic versions
396
+ compareVersions(v1: string, v2: string): number {
397
+ const parts1 = v1.split('.').map(Number);
398
+ const parts2 = v2.split('.').map(Number);
399
+
400
+ for (let i = 0; i < 3; i++) {
401
+ if (parts1[i] > parts2[i]) return 1;
402
+ if (parts1[i] < parts2[i]) return -1;
403
+ }
404
+
405
+ return 0;
406
+ }
407
+
408
+ // Check if update is major/minor/patch
409
+ getUpdateType(oldVersion: string, newVersion: string): string {
410
+ const [oldMajor, oldMinor, oldPatch] = oldVersion.split('.').map(Number);
411
+ const [newMajor, newMinor, newPatch] = newVersion.split('.').map(Number);
412
+
413
+ if (newMajor > oldMajor) return 'major';
414
+ if (newMinor > oldMinor) return 'minor';
415
+ if (newPatch > oldPatch) return 'patch';
416
+ return 'none';
417
+ }
418
+
419
+ // Determine update strategy based on version change
420
+ async determineStrategy(info: AppUpdateInfo) {
421
+ const updateType = this.getUpdateType(
422
+ info.currentVersion,
423
+ info.availableVersion
424
+ );
425
+
426
+ switch (updateType) {
427
+ case 'major':
428
+ // Major updates might need immediate update
429
+ return info.updatePriority >= 3 ? 'immediate' : 'flexible';
430
+
431
+ case 'minor':
432
+ // Minor updates are usually flexible
433
+ return 'flexible';
434
+
435
+ case 'patch':
436
+ // Patches can be optional unless critical
437
+ return info.updatePriority >= 4 ? 'flexible' : 'optional';
438
+
439
+ default:
440
+ return 'none';
441
+ }
442
+ }
443
+ }
444
+ ```
445
+
446
+ ### Minimum Version Enforcement
447
+
448
+ ```typescript
449
+ // Enforce minimum version requirements
450
+ async function enforceMinimumVersion() {
451
+ const config = {
452
+ appUpdate: {
453
+ minimumVersion: '2.0.0',
454
+ forceUpdateBelow: '1.5.0', // Force update for very old versions
455
+ },
456
+ };
457
+
458
+ const info = await CapacitorNativeUpdate.AppUpdate.getAppUpdateInfo();
459
+
460
+ // Check if current version is below minimum
461
+ if (isVersionBelow(info.currentVersion, config.appUpdate.minimumVersion)) {
462
+ // Force immediate update
463
+ try {
464
+ await CapacitorNativeUpdate.AppUpdate.performImmediateUpdate();
465
+ } catch (error) {
466
+ // If update fails or is cancelled, restrict app usage
467
+ showMinimumVersionRequired();
468
+ disableAppFeatures();
469
+ }
470
+ }
471
+ }
472
+ ```
473
+
474
+ ## Custom Update UI
475
+
476
+ ### Update Dialog Examples
477
+
478
+ ```typescript
479
+ // Custom update dialog
480
+ class UpdateUI {
481
+ showUpdateDialog(info: AppUpdateInfo) {
482
+ const dialog = {
483
+ title: this.getUpdateTitle(info),
484
+ message: this.getUpdateMessage(info),
485
+ buttons: this.getUpdateButtons(info),
486
+ };
487
+
488
+ return this.presentDialog(dialog);
489
+ }
490
+
491
+ private getUpdateTitle(info: AppUpdateInfo): string {
492
+ switch (info.updatePriority) {
493
+ case 5:
494
+ return '🚨 Critical Update Required';
495
+ case 4:
496
+ return '⚠️ Important Update Available';
497
+ case 3:
498
+ return '🎯 Recommended Update';
499
+ default:
500
+ return '✨ New Version Available';
501
+ }
502
+ }
503
+
504
+ private getUpdateMessage(info: AppUpdateInfo): string {
505
+ const size = this.formatBytes(info.updateSize);
506
+ const features = info.releaseNotes?.slice(0, 3).join('\n• ');
507
+
508
+ return `Version ${info.availableVersion} is available (${size})
509
+
510
+ What's new:
511
+ • ${features}
512
+
513
+ ${this.getUpdateUrgency(info)}`;
514
+ }
515
+
516
+ private getUpdateButtons(info: AppUpdateInfo): DialogButton[] {
517
+ if (info.updatePriority === 5) {
518
+ // Mandatory update - no cancel option
519
+ return [
520
+ {
521
+ text: 'Update Now',
522
+ handler: () => this.startUpdate(info),
523
+ },
524
+ ];
525
+ }
526
+
527
+ return [
528
+ {
529
+ text: 'Update',
530
+ handler: () => this.startUpdate(info),
531
+ },
532
+ {
533
+ text: 'Later',
534
+ role: 'cancel',
535
+ handler: () => this.scheduleReminder(info),
536
+ },
537
+ ];
538
+ }
539
+ }
540
+ ```
541
+
542
+ ### Progress Indicators
543
+
544
+ ```typescript
545
+ // Update progress UI
546
+ class UpdateProgressUI {
547
+ private progressBar: HTMLElement;
548
+ private statusText: HTMLElement;
549
+
550
+ showProgress() {
551
+ this.createProgressUI();
552
+
553
+ CapacitorNativeUpdate.AppUpdate.addListener(
554
+ 'flexibleUpdateProgress',
555
+ (progress) => {
556
+ this.updateProgress(progress);
557
+ }
558
+ );
559
+ }
560
+
561
+ private updateProgress(progress: UpdateProgress) {
562
+ // Update progress bar
563
+ this.progressBar.style.width = `${progress.percent}%`;
564
+
565
+ // Update status text
566
+ const downloaded = this.formatBytes(progress.bytesDownloaded);
567
+ const total = this.formatBytes(progress.totalBytes);
568
+ this.statusText.textContent = `Downloading: ${downloaded} / ${total}`;
569
+
570
+ // Show completion
571
+ if (progress.percent === 100) {
572
+ this.showCompletionUI();
573
+ }
574
+ }
575
+
576
+ private showCompletionUI() {
577
+ this.statusText.textContent = 'Update ready to install';
578
+ this.showInstallButton();
579
+ }
580
+ }
581
+ ```
582
+
583
+ ## Error Handling
584
+
585
+ ### Common Errors and Solutions
586
+
587
+ ```typescript
588
+ async function handleAppUpdateErrors() {
589
+ try {
590
+ await CapacitorNativeUpdate.AppUpdate.performImmediateUpdate();
591
+ } catch (error) {
592
+ switch (error.code) {
593
+ case 'UPDATE_NOT_AVAILABLE':
594
+ console.log('No update available');
595
+ break;
596
+
597
+ case 'UPDATE_CANCELLED':
598
+ // User cancelled the update
599
+ if (isCriticalUpdate()) {
600
+ showMandatoryUpdateMessage();
601
+ }
602
+ break;
603
+
604
+ case 'UPDATE_FAILED':
605
+ // Update failed to install
606
+ showRetryDialog();
607
+ break;
608
+
609
+ case 'PLATFORM_NOT_SUPPORTED':
610
+ // Feature not available on this platform
611
+ fallbackToManualUpdate();
612
+ break;
613
+
614
+ case 'PLAY_STORE_NOT_FOUND':
615
+ // Google Play Store not installed
616
+ showAlternativeUpdateMethod();
617
+ break;
618
+
619
+ case 'NETWORK_ERROR':
620
+ // No internet connection
621
+ showOfflineMessage();
622
+ scheduleRetryWhenOnline();
623
+ break;
624
+ }
625
+ }
626
+ }
627
+ ```
628
+
629
+ ### Retry Strategies
630
+
631
+ ```typescript
632
+ class UpdateRetryStrategy {
633
+ private retryCount = 0;
634
+ private maxRetries = 3;
635
+
636
+ async retryUpdate() {
637
+ try {
638
+ await CapacitorNativeUpdate.AppUpdate.startFlexibleUpdate();
639
+ this.retryCount = 0;
640
+ } catch (error) {
641
+ if (this.shouldRetry(error)) {
642
+ this.retryCount++;
643
+ const delay = this.calculateBackoff();
644
+
645
+ setTimeout(() => {
646
+ this.retryUpdate();
647
+ }, delay);
648
+ } else {
649
+ // Give up and show manual update option
650
+ this.showManualUpdateOption();
651
+ }
652
+ }
653
+ }
654
+
655
+ private calculateBackoff(): number {
656
+ // Exponential backoff: 2s, 4s, 8s
657
+ return Math.pow(2, this.retryCount) * 1000;
658
+ }
659
+ }
660
+ ```
661
+
662
+ ## Testing App Updates
663
+
664
+ ### Development Testing
665
+
666
+ ```typescript
667
+ // Mock update info for testing
668
+ const mockUpdateInfo: AppUpdateInfo = {
669
+ updateAvailable: true,
670
+ currentVersion: '1.0.0',
671
+ availableVersion: '2.0.0',
672
+ updatePriority: 4,
673
+ updateSize: 15 * 1024 * 1024, // 15MB
674
+ releaseNotes: [
675
+ 'New feature: Dark mode',
676
+ 'Performance improvements',
677
+ 'Bug fixes',
678
+ ],
679
+ isFlexibleUpdateAllowed: true,
680
+ isImmediateUpdateAllowed: true,
681
+ };
682
+
683
+ // Test different scenarios
684
+ async function testUpdateScenarios() {
685
+ // Test immediate update
686
+ await testImmediateUpdate();
687
+
688
+ // Test flexible update
689
+ await testFlexibleUpdate();
690
+
691
+ // Test update cancellation
692
+ await testUpdateCancellation();
693
+
694
+ // Test network errors
695
+ await testNetworkErrors();
696
+ }
697
+ ```
698
+
699
+ ### Platform-Specific Testing
700
+
701
+ ```bash
702
+ # Android testing with internal app sharing
703
+ # 1. Build APK with higher version number
704
+ # 2. Upload to Play Console internal app sharing
705
+ # 3. Install lower version on device
706
+ # 4. Test update flow
707
+
708
+ # iOS testing with TestFlight
709
+ # 1. Upload new version to TestFlight
710
+ # 2. Install older version
711
+ # 3. Test update detection and App Store redirect
712
+ ```
713
+
714
+ ## Best Practices
715
+
716
+ ### 1. User Experience
717
+
718
+ ```typescript
719
+ // Provide clear update information
720
+ const updateMessage = {
721
+ title: 'Exciting Update!',
722
+ features: [
723
+ '🎨 Beautiful new design',
724
+ '⚡ 2x faster performance',
725
+ '🐛 Bug fixes and improvements',
726
+ ],
727
+ size: '12 MB',
728
+ time: 'Less than 1 minute',
729
+ };
730
+ ```
731
+
732
+ ### 2. Smart Scheduling
733
+
734
+ ```typescript
735
+ // Update at appropriate times
736
+ class SmartUpdateScheduler {
737
+ async scheduleUpdate(info: AppUpdateInfo) {
738
+ // Don't interrupt critical user flows
739
+ if (this.isUserInCriticalFlow()) {
740
+ this.scheduleForLater();
741
+ return;
742
+ }
743
+
744
+ // Check device conditions
745
+ const conditions = await this.checkDeviceConditions();
746
+
747
+ if (conditions.isCharging && conditions.onWifi) {
748
+ // Ideal conditions - start update
749
+ await this.startUpdate();
750
+ } else {
751
+ // Wait for better conditions
752
+ this.waitForBetterConditions();
753
+ }
754
+ }
755
+ }
756
+ ```
757
+
758
+ ### 3. Analytics Integration
759
+
760
+ ```typescript
761
+ // Track update metrics
762
+ async function trackUpdateMetrics(event: string, data: any) {
763
+ await analytics.track({
764
+ event: `app_update_${event}`,
765
+ properties: {
766
+ currentVersion: data.currentVersion,
767
+ availableVersion: data.availableVersion,
768
+ updatePriority: data.updatePriority,
769
+ userAction: data.userAction,
770
+ timestamp: Date.now(),
771
+ },
772
+ });
773
+ }
774
+ ```
775
+
776
+ ## Next Steps
777
+
778
+ - Configure [App Reviews](./app-reviews.md) for user feedback
779
+ - Implement [Security Best Practices](../guides/security-best-practices.md)
780
+ - Set up [Update Monitoring](../guides/monitoring.md)
781
+ - Review [API Reference](../api/app-update-api.md)
782
+
783
+ ---
784
+
785
+ Made with ❤️ by Ahsan Mahmood