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,694 @@
1
+ # Native App Updates Implementation Guide
2
+
3
+ This comprehensive guide explains how to implement Native App Updates (App Store and Google Play updates) in your Capacitor application using the CapacitorNativeUpdate plugin.
4
+
5
+ ## Table of Contents
6
+
7
+ - [Overview](#overview)
8
+ - [Platform Differences](#platform-differences)
9
+ - [Setup Guide](#setup-guide)
10
+ - [Implementation Steps](#implementation-steps)
11
+ - [UI/UX Best Practices](#uiux-best-practices)
12
+ - [Testing](#testing)
13
+ - [Troubleshooting](#troubleshooting)
14
+
15
+ ## Overview
16
+
17
+ Native App Updates allow your app to:
18
+
19
+ - 🔄 Check for new versions in app stores
20
+ - 📥 Download updates within the app
21
+ - 🚀 Install updates seamlessly
22
+ - 📊 Track update adoption rates
23
+
24
+ ### Benefits
25
+
26
+ - **User Experience**: Users update without leaving your app
27
+ - **Adoption Rate**: Higher update rates vs waiting for manual updates
28
+ - **Control**: Guide users through important updates
29
+ - **Flexibility**: Immediate vs flexible update strategies
30
+
31
+ ## Platform Differences
32
+
33
+ ### Android (Google Play)
34
+
35
+ - Uses Google Play Core Library
36
+ - Supports In-App Updates API
37
+ - Two update modes: Immediate and Flexible
38
+ - Requires Google Play Store (not available on other stores)
39
+
40
+ ### iOS (App Store)
41
+
42
+ - Uses StoreKit framework
43
+ - Redirects to App Store for download
44
+ - Cannot install directly within app
45
+ - Shows update availability only
46
+
47
+ ## Setup Guide
48
+
49
+ ### Prerequisites
50
+
51
+ 1. **Android**:
52
+ - App must be published on Google Play Store
53
+ - Minimum API level 21 (Android 5.0)
54
+ - Google Play Core library
55
+
56
+ 2. **iOS**:
57
+ - App must be published on Apple App Store
58
+ - iOS 10.0 or higher
59
+ - Valid App Store ID
60
+
61
+ ### Installation
62
+
63
+ ```bash
64
+ npm install capacitor-native-update
65
+ npx cap sync
66
+ ```
67
+
68
+ ### Android Configuration
69
+
70
+ 1. **Add to `android/app/build.gradle`:**
71
+
72
+ ```gradle
73
+ dependencies {
74
+ implementation 'com.google.android.play:core:2.1.0'
75
+ implementation 'com.google.android.play:core-ktx:1.8.1'
76
+ }
77
+ ```
78
+
79
+ 2. **Add to `AndroidManifest.xml`:**
80
+
81
+ ```xml
82
+ <uses-permission android:name="android.permission.INTERNET" />
83
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
84
+ ```
85
+
86
+ ### iOS Configuration
87
+
88
+ 1. **Add to `Info.plist`:**
89
+
90
+ ```xml
91
+ <key>LSApplicationQueriesSchemes</key>
92
+ <array>
93
+ <string>itms-apps</string>
94
+ </array>
95
+ ```
96
+
97
+ 2. **Enable Capabilities in Xcode:**
98
+ - App Groups (for shared data)
99
+ - Background Modes > Background fetch
100
+
101
+ ## Implementation Steps
102
+
103
+ ### Step 1: Basic Implementation
104
+
105
+ ```typescript
106
+ import { CapacitorNativeUpdate } from 'capacitor-native-update';
107
+ import { Capacitor } from '@capacitor/core';
108
+
109
+ export class NativeUpdateService {
110
+ async checkForAppUpdate() {
111
+ try {
112
+ // Check current platform
113
+ const platform = Capacitor.getPlatform();
114
+
115
+ // Check for native app updates
116
+ const result = await CapacitorNativeUpdate.checkAppUpdate();
117
+
118
+ if (result.updateAvailable) {
119
+ console.log(`Update available: ${result.availableVersion}`);
120
+ console.log(`Current version: ${result.currentVersion}`);
121
+
122
+ // Handle based on update type
123
+ if (result.immediateUpdateAllowed) {
124
+ await this.performImmediateUpdate();
125
+ } else if (result.flexibleUpdateAllowed) {
126
+ await this.performFlexibleUpdate();
127
+ } else if (platform === 'ios') {
128
+ await this.redirectToAppStore();
129
+ }
130
+ }
131
+ } catch (error) {
132
+ console.error('Update check failed:', error);
133
+ }
134
+ }
135
+ }
136
+ ```
137
+
138
+ ### Step 2: Android In-App Updates
139
+
140
+ #### Immediate Update (Blocking)
141
+
142
+ ```typescript
143
+ export class AndroidImmediateUpdate {
144
+ async performImmediateUpdate() {
145
+ try {
146
+ // Start immediate update
147
+ const { started } = await CapacitorNativeUpdate.startImmediateUpdate();
148
+
149
+ if (started) {
150
+ // The app will be restarted automatically after update
151
+ console.log('Immediate update started');
152
+ }
153
+ } catch (error) {
154
+ if (error.code === 'UPDATE_CANCELED') {
155
+ // User canceled the update
156
+ // For immediate updates, you might want to close the app
157
+ await this.showMandatoryUpdateDialog();
158
+ }
159
+ }
160
+ }
161
+
162
+ async showMandatoryUpdateDialog() {
163
+ const alert = await this.alertController.create({
164
+ header: 'Update Required',
165
+ message: 'This update is required to continue using the app.',
166
+ backdropDismiss: false,
167
+ buttons: [
168
+ {
169
+ text: 'Update',
170
+ handler: () => {
171
+ this.performImmediateUpdate();
172
+ },
173
+ },
174
+ ],
175
+ });
176
+ await alert.present();
177
+ }
178
+ }
179
+ ```
180
+
181
+ #### Flexible Update (Non-blocking)
182
+
183
+ ```typescript
184
+ export class AndroidFlexibleUpdate {
185
+ private updateDownloaded = false;
186
+
187
+ async performFlexibleUpdate() {
188
+ try {
189
+ // Start flexible update
190
+ await CapacitorNativeUpdate.startFlexibleUpdate();
191
+
192
+ // Listen for download progress
193
+ CapacitorNativeUpdate.addListener(
194
+ 'onAppUpdateDownloadProgress',
195
+ (progress) => {
196
+ console.log(
197
+ `Download progress: ${progress.bytesDownloaded} / ${progress.totalBytesToDownload}`
198
+ );
199
+ this.updateProgressUI(progress);
200
+ }
201
+ );
202
+
203
+ // Listen for download completion
204
+ CapacitorNativeUpdate.addListener('onAppUpdateDownloaded', () => {
205
+ console.log('Update downloaded');
206
+ this.updateDownloaded = true;
207
+ this.showInstallPrompt();
208
+ });
209
+ } catch (error) {
210
+ console.error('Flexible update failed:', error);
211
+ }
212
+ }
213
+
214
+ async showInstallPrompt() {
215
+ const alert = await this.alertController.create({
216
+ header: 'Update Ready',
217
+ message:
218
+ 'A new version has been downloaded. Would you like to install it now?',
219
+ buttons: [
220
+ {
221
+ text: 'Later',
222
+ role: 'cancel',
223
+ handler: () => {
224
+ // Install will happen on next app restart
225
+ },
226
+ },
227
+ {
228
+ text: 'Install',
229
+ handler: () => {
230
+ this.completeFlexibleUpdate();
231
+ },
232
+ },
233
+ ],
234
+ });
235
+ await alert.present();
236
+ }
237
+
238
+ async completeFlexibleUpdate() {
239
+ try {
240
+ await CapacitorNativeUpdate.completeFlexibleUpdate();
241
+ // App will restart with new version
242
+ } catch (error) {
243
+ console.error('Failed to complete update:', error);
244
+ }
245
+ }
246
+
247
+ updateProgressUI(progress: any) {
248
+ const percent = Math.round(
249
+ (progress.bytesDownloaded / progress.totalBytesToDownload) * 100
250
+ );
251
+
252
+ // Update your UI progress bar
253
+ this.downloadProgress = percent;
254
+ }
255
+ }
256
+ ```
257
+
258
+ ### Step 3: iOS App Store Updates
259
+
260
+ ```typescript
261
+ export class iOSAppStoreUpdate {
262
+ async checkAndPromptUpdate() {
263
+ try {
264
+ const result = await CapacitorNativeUpdate.checkAppUpdate();
265
+
266
+ if (result.updateAvailable) {
267
+ await this.showiOSUpdateDialog(result);
268
+ }
269
+ } catch (error) {
270
+ console.error('iOS update check failed:', error);
271
+ }
272
+ }
273
+
274
+ async showiOSUpdateDialog(updateInfo: any) {
275
+ const alert = await this.alertController.create({
276
+ header: 'Update Available',
277
+ message: `Version ${updateInfo.availableVersion} is available on the App Store.`,
278
+ buttons: [
279
+ {
280
+ text: 'Later',
281
+ role: 'cancel',
282
+ },
283
+ {
284
+ text: 'Update',
285
+ handler: () => {
286
+ this.openAppStore();
287
+ },
288
+ },
289
+ ],
290
+ });
291
+ await alert.present();
292
+ }
293
+
294
+ async openAppStore() {
295
+ try {
296
+ await CapacitorNativeUpdate.openAppStore();
297
+ } catch (error) {
298
+ // Fallback to browser
299
+ const appStoreUrl = `https://apps.apple.com/app/id${YOUR_APP_STORE_ID}`;
300
+ window.open(appStoreUrl, '_system');
301
+ }
302
+ }
303
+ }
304
+ ```
305
+
306
+ ### Step 4: Cross-Platform Implementation
307
+
308
+ ```typescript
309
+ import { Capacitor } from '@capacitor/core';
310
+ import { CapacitorNativeUpdate } from 'capacitor-native-update';
311
+
312
+ export class UnifiedUpdateService {
313
+ private platform = Capacitor.getPlatform();
314
+
315
+ async checkAndUpdateApp() {
316
+ try {
317
+ const updateInfo = await CapacitorNativeUpdate.checkAppUpdate();
318
+
319
+ if (!updateInfo.updateAvailable) {
320
+ console.log('App is up to date');
321
+ return;
322
+ }
323
+
324
+ // Platform-specific handling
325
+ if (this.platform === 'android') {
326
+ await this.handleAndroidUpdate(updateInfo);
327
+ } else if (this.platform === 'ios') {
328
+ await this.handleiOSUpdate(updateInfo);
329
+ }
330
+ } catch (error) {
331
+ console.error('Update check failed:', error);
332
+ this.handleUpdateError(error);
333
+ }
334
+ }
335
+
336
+ private async handleAndroidUpdate(updateInfo: any) {
337
+ // Determine update priority
338
+ const priority = updateInfo.updatePriority || 0;
339
+
340
+ if (priority >= 4 || updateInfo.immediateUpdateAllowed) {
341
+ // High priority or immediate update required
342
+ await this.showUpdateDialog({
343
+ title: 'Important Update',
344
+ message: 'A critical update is available and must be installed.',
345
+ mandatory: true,
346
+ action: () => this.performImmediateUpdate(),
347
+ });
348
+ } else if (updateInfo.flexibleUpdateAllowed) {
349
+ // Normal priority - flexible update
350
+ await this.showUpdateDialog({
351
+ title: 'Update Available',
352
+ message: `Version ${updateInfo.availableVersion} is available with new features and improvements.`,
353
+ mandatory: false,
354
+ action: () => this.performFlexibleUpdate(),
355
+ });
356
+ }
357
+ }
358
+
359
+ private async handleiOSUpdate(updateInfo: any) {
360
+ await this.showUpdateDialog({
361
+ title: 'Update Available',
362
+ message: `Version ${updateInfo.availableVersion} is available on the App Store.`,
363
+ mandatory: false,
364
+ action: () => CapacitorNativeUpdate.openAppStore(),
365
+ });
366
+ }
367
+
368
+ private async showUpdateDialog(options: {
369
+ title: string;
370
+ message: string;
371
+ mandatory: boolean;
372
+ action: () => Promise<void>;
373
+ }) {
374
+ const buttons = options.mandatory
375
+ ? [
376
+ {
377
+ text: 'Update Now',
378
+ handler: () => options.action(),
379
+ },
380
+ ]
381
+ : [
382
+ {
383
+ text: 'Later',
384
+ role: 'cancel',
385
+ },
386
+ {
387
+ text: 'Update',
388
+ handler: () => options.action(),
389
+ },
390
+ ];
391
+
392
+ const alert = await this.alertController.create({
393
+ header: options.title,
394
+ message: options.message,
395
+ backdropDismiss: !options.mandatory,
396
+ buttons,
397
+ });
398
+
399
+ await alert.present();
400
+ }
401
+ }
402
+ ```
403
+
404
+ ### Step 5: Update Status Handling
405
+
406
+ ```typescript
407
+ export class UpdateStatusManager {
408
+ constructor() {
409
+ this.setupUpdateListeners();
410
+ }
411
+
412
+ private setupUpdateListeners() {
413
+ // Installation status
414
+ CapacitorNativeUpdate.addListener('onAppUpdateInstallStatus', (status) => {
415
+ switch (status.status) {
416
+ case 'PENDING':
417
+ console.log('Update pending');
418
+ break;
419
+ case 'DOWNLOADING':
420
+ console.log('Downloading update');
421
+ break;
422
+ case 'INSTALLING':
423
+ console.log('Installing update');
424
+ break;
425
+ case 'INSTALLED':
426
+ console.log('Update installed');
427
+ this.notifyUpdateComplete();
428
+ break;
429
+ case 'FAILED':
430
+ console.error('Update failed:', status.error);
431
+ this.handleUpdateFailure(status.error);
432
+ break;
433
+ case 'CANCELED':
434
+ console.log('Update canceled by user');
435
+ break;
436
+ }
437
+ });
438
+
439
+ // Download progress (Android flexible updates)
440
+ CapacitorNativeUpdate.addListener(
441
+ 'onAppUpdateDownloadProgress',
442
+ (progress) => {
443
+ const percent = Math.round(
444
+ (progress.bytesDownloaded / progress.totalBytesToDownload) * 100
445
+ );
446
+ this.updateProgressBar(percent);
447
+ }
448
+ );
449
+ }
450
+
451
+ private updateProgressBar(percent: number) {
452
+ // Update your UI
453
+ const progressBar = document.querySelector('.update-progress');
454
+ if (progressBar) {
455
+ progressBar.setAttribute('value', percent.toString());
456
+ }
457
+ }
458
+ }
459
+ ```
460
+
461
+ ## UI/UX Best Practices
462
+
463
+ ### 1. Update Prompts
464
+
465
+ ```typescript
466
+ export class UpdateUIService {
467
+ async showSmartUpdatePrompt(updateInfo: any) {
468
+ const timeSinceLastPrompt = Date.now() - this.lastPromptTime;
469
+ const oneDayInMs = 24 * 60 * 60 * 1000;
470
+
471
+ // Don't prompt too frequently
472
+ if (timeSinceLastPrompt < oneDayInMs && !updateInfo.mandatory) {
473
+ return;
474
+ }
475
+
476
+ // Custom UI based on update importance
477
+ if (updateInfo.updatePriority >= 4) {
478
+ await this.showCriticalUpdateUI(updateInfo);
479
+ } else if (updateInfo.releaseNotes?.includes('security')) {
480
+ await this.showSecurityUpdateUI(updateInfo);
481
+ } else {
482
+ await this.showStandardUpdateUI(updateInfo);
483
+ }
484
+
485
+ this.lastPromptTime = Date.now();
486
+ }
487
+
488
+ private async showCriticalUpdateUI(updateInfo: any) {
489
+ // Full-screen modal for critical updates
490
+ const modal = await this.modalController.create({
491
+ component: CriticalUpdateComponent,
492
+ componentProps: { updateInfo },
493
+ backdropDismiss: false,
494
+ });
495
+ await modal.present();
496
+ }
497
+
498
+ private async showStandardUpdateUI(updateInfo: any) {
499
+ // Toast or small banner for standard updates
500
+ const toast = await this.toastController.create({
501
+ message: 'A new version is available',
502
+ duration: 5000,
503
+ position: 'top',
504
+ buttons: [
505
+ {
506
+ text: 'Update',
507
+ handler: () => this.startUpdate(),
508
+ },
509
+ ],
510
+ });
511
+ await toast.present();
512
+ }
513
+ }
514
+ ```
515
+
516
+ ### 2. Progress Indicators
517
+
518
+ ```html
519
+ <!-- update-progress.component.html -->
520
+ <ion-card *ngIf="updateInProgress">
521
+ <ion-card-header>
522
+ <ion-card-title>Updating App</ion-card-title>
523
+ </ion-card-header>
524
+ <ion-card-content>
525
+ <ion-progress-bar [value]="downloadProgress / 100"></ion-progress-bar>
526
+ <p>{{ downloadProgress }}% complete</p>
527
+ <p class="update-status">{{ updateStatus }}</p>
528
+ </ion-card-content>
529
+ </ion-card>
530
+ ```
531
+
532
+ ### 3. Smart Update Scheduling
533
+
534
+ ```typescript
535
+ export class SmartUpdateScheduler {
536
+ async scheduleUpdate() {
537
+ const updateInfo = await CapacitorNativeUpdate.checkAppUpdate();
538
+
539
+ if (!updateInfo.updateAvailable) return;
540
+
541
+ // Check user preferences
542
+ const preferences = await this.getUpdatePreferences();
543
+
544
+ if (preferences.autoUpdate === 'wifi-only') {
545
+ const connection = await Network.getStatus();
546
+ if (connection.connectionType !== 'wifi') {
547
+ // Schedule for later when on WiFi
548
+ this.scheduleForWiFi();
549
+ return;
550
+ }
551
+ }
552
+
553
+ if (preferences.autoUpdate === 'night-only') {
554
+ const hour = new Date().getHours();
555
+ if (hour >= 6 && hour <= 22) {
556
+ // Schedule for nighttime
557
+ this.scheduleForNight();
558
+ return;
559
+ }
560
+ }
561
+
562
+ // Proceed with update
563
+ await this.performUpdate();
564
+ }
565
+ }
566
+ ```
567
+
568
+ ## Testing
569
+
570
+ ### Android Testing
571
+
572
+ 1. **Using Internal Test Track**:
573
+
574
+ ```typescript
575
+ // Enable internal app sharing for testing
576
+ await CapacitorNativeUpdate.enableDebugMode({
577
+ enabled: true,
578
+ testMode: 'internal-test',
579
+ });
580
+ ```
581
+
582
+ 2. **Test Different Scenarios**:
583
+
584
+ ```typescript
585
+ // Test immediate update
586
+ await CapacitorNativeUpdate.simulateUpdate({
587
+ type: 'immediate',
588
+ version: '2.0.0',
589
+ });
590
+
591
+ // Test flexible update
592
+ await CapacitorNativeUpdate.simulateUpdate({
593
+ type: 'flexible',
594
+ version: '1.1.0',
595
+ });
596
+ ```
597
+
598
+ ### iOS Testing
599
+
600
+ 1. **TestFlight Testing**:
601
+ - Upload build to TestFlight
602
+ - Install older version on device
603
+ - Check for updates in app
604
+
605
+ 2. **Sandbox Testing**:
606
+ - Use sandbox App Store account
607
+ - Test update flow without affecting production
608
+
609
+ ### Testing Checklist
610
+
611
+ - [ ] Update available detection
612
+ - [ ] Update not available scenario
613
+ - [ ] Immediate update flow (Android)
614
+ - [ ] Flexible update flow (Android)
615
+ - [ ] App Store redirect (iOS)
616
+ - [ ] Update cancellation handling
617
+ - [ ] Network error handling
618
+ - [ ] Update completion verification
619
+ - [ ] Rollback scenarios (if applicable)
620
+
621
+ ## Troubleshooting
622
+
623
+ ### Common Issues
624
+
625
+ #### 1. Update Not Detected
626
+
627
+ ```typescript
628
+ // Debug update detection
629
+ const debug = await CapacitorNativeUpdate.getDebugInfo();
630
+ console.log('Debug info:', {
631
+ currentVersion: debug.currentVersion,
632
+ packageName: debug.packageName,
633
+ lastCheckTime: debug.lastCheckTime,
634
+ playServicesAvailable: debug.playServicesAvailable, // Android
635
+ });
636
+ ```
637
+
638
+ #### 2. Update Fails to Install
639
+
640
+ ```typescript
641
+ // Check update state
642
+ const state = await CapacitorNativeUpdate.getUpdateState();
643
+ if (state.status === 'FAILED') {
644
+ // Clear update data and retry
645
+ await CapacitorNativeUpdate.clearUpdateData();
646
+ await CapacitorNativeUpdate.checkAppUpdate();
647
+ }
648
+ ```
649
+
650
+ #### 3. iOS App Store Not Opening
651
+
652
+ ```typescript
653
+ // Verify App Store ID configuration
654
+ const config = await CapacitorNativeUpdate.getConfiguration();
655
+ console.log('App Store ID:', config.appStoreId);
656
+
657
+ // Manual fallback
658
+ if (!config.appStoreId) {
659
+ console.error('App Store ID not configured');
660
+ }
661
+ ```
662
+
663
+ ### Platform-Specific Issues
664
+
665
+ #### Android
666
+
667
+ - Ensure Google Play Services is updated
668
+ - Check Play Store app is installed
669
+ - Verify app is signed with release key
670
+ - Test on device with Play Store (not emulator)
671
+
672
+ #### iOS
673
+
674
+ - Verify App Store ID is correct
675
+ - Check iTunes lookup API response
676
+ - Ensure app is live on App Store
677
+ - Test on real device (not simulator)
678
+
679
+ ## Best Practices Summary
680
+
681
+ 1. **Always provide "Later" option** for non-critical updates
682
+ 2. **Show release notes** when available
683
+ 3. **Respect user preferences** for update timing
684
+ 4. **Handle network conditions** appropriately
685
+ 5. **Test thoroughly** on both platforms
686
+ 6. **Monitor update metrics** to improve adoption
687
+ 7. **Provide fallback options** for update failures
688
+
689
+ ## Next Steps
690
+
691
+ - Learn about [Live Updates (OTA)](./LIVE_UPDATES_GUIDE.md)
692
+ - Implement [App Review Features](./APP_REVIEW_GUIDE.md)
693
+ - Review [Security Guidelines](./SECURITY.md)
694
+ - Check [API Reference](../API.md)