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.
- package/CapacitorNativeUpdate.podspec +18 -0
- package/LICENSE +21 -0
- package/Readme.md +451 -0
- package/android/build.gradle +92 -0
- package/android/gradle/wrapper/gradle-wrapper.properties +8 -0
- package/android/gradle.properties +17 -0
- package/android/proguard-rules.pro +29 -0
- package/android/settings.gradle +2 -0
- package/android/src/main/AndroidManifest.xml +34 -0
- package/android/src/main/java/com/aoneahsan/nativeupdate/AppReviewPlugin.kt +153 -0
- package/android/src/main/java/com/aoneahsan/nativeupdate/AppUpdatePlugin.kt +275 -0
- package/android/src/main/java/com/aoneahsan/nativeupdate/BackgroundNotificationManager.kt +390 -0
- package/android/src/main/java/com/aoneahsan/nativeupdate/BackgroundUpdateManager.kt +46 -0
- package/android/src/main/java/com/aoneahsan/nativeupdate/BackgroundUpdatePlugin.kt +333 -0
- package/android/src/main/java/com/aoneahsan/nativeupdate/BackgroundUpdateWorker.kt +251 -0
- package/android/src/main/java/com/aoneahsan/nativeupdate/CapacitorNativeUpdatePlugin.kt +265 -0
- package/android/src/main/java/com/aoneahsan/nativeupdate/LiveUpdatePlugin.kt +526 -0
- package/android/src/main/java/com/aoneahsan/nativeupdate/NotificationActionReceiver.kt +99 -0
- package/android/src/main/java/com/aoneahsan/nativeupdate/SecurityManager.kt +249 -0
- package/dist/esm/__tests__/bundle-manager.test.d.ts +1 -0
- package/dist/esm/__tests__/bundle-manager.test.js +123 -0
- package/dist/esm/__tests__/bundle-manager.test.js.map +1 -0
- package/dist/esm/__tests__/config.test.d.ts +1 -0
- package/dist/esm/__tests__/config.test.js +69 -0
- package/dist/esm/__tests__/config.test.js.map +1 -0
- package/dist/esm/__tests__/integration.test.d.ts +1 -0
- package/dist/esm/__tests__/integration.test.js +78 -0
- package/dist/esm/__tests__/integration.test.js.map +1 -0
- package/dist/esm/__tests__/security.test.d.ts +1 -0
- package/dist/esm/__tests__/security.test.js +54 -0
- package/dist/esm/__tests__/security.test.js.map +1 -0
- package/dist/esm/__tests__/version-manager.test.d.ts +1 -0
- package/dist/esm/__tests__/version-manager.test.js +45 -0
- package/dist/esm/__tests__/version-manager.test.js.map +1 -0
- package/dist/esm/app-review/app-review-manager.d.ts +24 -0
- package/dist/esm/app-review/app-review-manager.js +195 -0
- package/dist/esm/app-review/app-review-manager.js.map +1 -0
- package/dist/esm/app-review/index.d.ts +5 -0
- package/dist/esm/app-review/index.js +6 -0
- package/dist/esm/app-review/index.js.map +1 -0
- package/dist/esm/app-review/platform-review-handler.d.ts +20 -0
- package/dist/esm/app-review/platform-review-handler.js +138 -0
- package/dist/esm/app-review/platform-review-handler.js.map +1 -0
- package/dist/esm/app-review/review-conditions-checker.d.ts +22 -0
- package/dist/esm/app-review/review-conditions-checker.js +155 -0
- package/dist/esm/app-review/review-conditions-checker.js.map +1 -0
- package/dist/esm/app-review/review-rate-limiter.d.ts +23 -0
- package/dist/esm/app-review/review-rate-limiter.js +164 -0
- package/dist/esm/app-review/review-rate-limiter.js.map +1 -0
- package/dist/esm/app-review/types.d.ts +41 -0
- package/dist/esm/app-review/types.js +2 -0
- package/dist/esm/app-review/types.js.map +1 -0
- package/dist/esm/app-update/app-update-checker.d.ts +13 -0
- package/dist/esm/app-update/app-update-checker.js +104 -0
- package/dist/esm/app-update/app-update-checker.js.map +1 -0
- package/dist/esm/app-update/app-update-installer.d.ts +19 -0
- package/dist/esm/app-update/app-update-installer.js +123 -0
- package/dist/esm/app-update/app-update-installer.js.map +1 -0
- package/dist/esm/app-update/app-update-manager.d.ts +28 -0
- package/dist/esm/app-update/app-update-manager.js +199 -0
- package/dist/esm/app-update/app-update-manager.js.map +1 -0
- package/dist/esm/app-update/app-update-notifier.d.ts +14 -0
- package/dist/esm/app-update/app-update-notifier.js +100 -0
- package/dist/esm/app-update/app-update-notifier.js.map +1 -0
- package/dist/esm/app-update/index.d.ts +6 -0
- package/dist/esm/app-update/index.js +7 -0
- package/dist/esm/app-update/index.js.map +1 -0
- package/dist/esm/app-update/platform-app-update.d.ts +19 -0
- package/dist/esm/app-update/platform-app-update.js +129 -0
- package/dist/esm/app-update/platform-app-update.js.map +1 -0
- package/dist/esm/app-update/types.d.ts +58 -0
- package/dist/esm/app-update/types.js +12 -0
- package/dist/esm/app-update/types.js.map +1 -0
- package/dist/esm/background-update/background-scheduler.d.ts +17 -0
- package/dist/esm/background-update/background-scheduler.js +195 -0
- package/dist/esm/background-update/background-scheduler.js.map +1 -0
- package/dist/esm/background-update/index.d.ts +3 -0
- package/dist/esm/background-update/index.js +3 -0
- package/dist/esm/background-update/index.js.map +1 -0
- package/dist/esm/background-update/notification-manager.d.ts +29 -0
- package/dist/esm/background-update/notification-manager.js +89 -0
- package/dist/esm/background-update/notification-manager.js.map +1 -0
- package/dist/esm/core/analytics.d.ts +70 -0
- package/dist/esm/core/analytics.js +137 -0
- package/dist/esm/core/analytics.js.map +1 -0
- package/dist/esm/core/cache-manager.d.ts +72 -0
- package/dist/esm/core/cache-manager.js +275 -0
- package/dist/esm/core/cache-manager.js.map +1 -0
- package/dist/esm/core/config.d.ts +48 -0
- package/dist/esm/core/config.js +83 -0
- package/dist/esm/core/config.js.map +1 -0
- package/dist/esm/core/errors.d.ts +51 -0
- package/dist/esm/core/errors.js +80 -0
- package/dist/esm/core/errors.js.map +1 -0
- package/dist/esm/core/logger.d.ts +21 -0
- package/dist/esm/core/logger.js +109 -0
- package/dist/esm/core/logger.js.map +1 -0
- package/dist/esm/core/performance.d.ts +53 -0
- package/dist/esm/core/performance.js +140 -0
- package/dist/esm/core/performance.js.map +1 -0
- package/dist/esm/core/plugin-manager.d.ts +66 -0
- package/dist/esm/core/plugin-manager.js +148 -0
- package/dist/esm/core/plugin-manager.js.map +1 -0
- package/dist/esm/core/security.d.ts +93 -0
- package/dist/esm/core/security.js +315 -0
- package/dist/esm/core/security.js.map +1 -0
- package/dist/esm/definitions.d.ts +639 -0
- package/dist/esm/definitions.js +103 -0
- package/dist/esm/definitions.js.map +1 -0
- package/dist/esm/index.d.ts +12 -0
- package/dist/esm/index.js +16 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/live-update/bundle-manager.d.ts +94 -0
- package/dist/esm/live-update/bundle-manager.js +310 -0
- package/dist/esm/live-update/bundle-manager.js.map +1 -0
- package/dist/esm/live-update/certificate-pinning.d.ts +38 -0
- package/dist/esm/live-update/certificate-pinning.js +78 -0
- package/dist/esm/live-update/certificate-pinning.js.map +1 -0
- package/dist/esm/live-update/download-manager.d.ts +67 -0
- package/dist/esm/live-update/download-manager.js +319 -0
- package/dist/esm/live-update/download-manager.js.map +1 -0
- package/dist/esm/live-update/update-manager.d.ts +52 -0
- package/dist/esm/live-update/update-manager.js +294 -0
- package/dist/esm/live-update/update-manager.js.map +1 -0
- package/dist/esm/live-update/version-manager.d.ts +84 -0
- package/dist/esm/live-update/version-manager.js +335 -0
- package/dist/esm/live-update/version-manager.js.map +1 -0
- package/dist/esm/plugin.d.ts +6 -0
- package/dist/esm/plugin.js +283 -0
- package/dist/esm/plugin.js.map +1 -0
- package/dist/esm/security/crypto.d.ts +25 -0
- package/dist/esm/security/crypto.js +70 -0
- package/dist/esm/security/crypto.js.map +1 -0
- package/dist/esm/security/validator.d.ts +60 -0
- package/dist/esm/security/validator.js +143 -0
- package/dist/esm/security/validator.js.map +1 -0
- package/dist/esm/web.d.ts +74 -0
- package/dist/esm/web.js +595 -0
- package/dist/esm/web.js.map +1 -0
- package/dist/plugin.cjs.js +2 -0
- package/dist/plugin.cjs.js.map +1 -0
- package/dist/plugin.esm.js +2 -0
- package/dist/plugin.esm.js.map +1 -0
- package/dist/plugin.js +3 -0
- package/dist/plugin.js.map +1 -0
- package/docs/APP_REVIEW_GUIDE.md +768 -0
- package/docs/BUNDLE_SIGNING.md +264 -0
- package/docs/LIVE_UPDATES_GUIDE.md +650 -0
- package/docs/MIGRATION.md +192 -0
- package/docs/NATIVE_UPDATES_GUIDE.md +694 -0
- package/docs/QUICK_START.md +606 -0
- package/docs/README.md +111 -0
- package/docs/REMAINING_FEATURES.md +139 -0
- package/docs/api/app-review-api.md +259 -0
- package/docs/api/app-update-api.md +238 -0
- package/docs/api/events-api.md +451 -0
- package/docs/api/live-update-api.md +265 -0
- package/docs/background-updates.md +392 -0
- package/docs/examples/advanced-scenarios.md +410 -0
- package/docs/examples/basic-usage.md +185 -0
- package/docs/features/app-reviews.md +975 -0
- package/docs/features/app-updates.md +785 -0
- package/docs/features/live-updates.md +633 -0
- package/docs/getting-started/configuration.md +468 -0
- package/docs/getting-started/installation.md +209 -0
- package/docs/getting-started/quick-start.md +379 -0
- package/docs/guides/deployment-guide.md +333 -0
- package/docs/guides/migration-from-codepush.md +142 -0
- package/docs/guides/security-best-practices.md +1057 -0
- package/docs/guides/testing-guide.md +373 -0
- package/docs/production-readiness.md +478 -0
- package/docs/security/certificate-pinning.md +122 -0
- package/docs/server-requirements.md +147 -0
- package/ios/Plugin/AppReview/AppReviewPlugin.swift +158 -0
- package/ios/Plugin/AppUpdate/AppUpdatePlugin.swift +234 -0
- package/ios/Plugin/BackgroundUpdate/BackgroundNotificationManager.swift +329 -0
- package/ios/Plugin/BackgroundUpdate/BackgroundUpdatePlugin.swift +396 -0
- package/ios/Plugin/CapacitorNativeUpdatePlugin.m +45 -0
- package/ios/Plugin/CapacitorNativeUpdatePlugin.swift +190 -0
- package/ios/Plugin/Info.plist +43 -0
- package/ios/Plugin/LiveUpdate/LiveUpdatePlugin.swift +689 -0
- package/ios/Plugin/LiveUpdate/WebViewConfiguration.swift +45 -0
- package/ios/Plugin/Security/SecurityManager.swift +289 -0
- package/package.json +90 -0
|
@@ -0,0 +1,650 @@
|
|
|
1
|
+
# Live Updates (OTA) Implementation Guide
|
|
2
|
+
|
|
3
|
+
This comprehensive guide explains how to implement Live Updates (Over-The-Air updates) in your Capacitor application using the CapacitorNativeUpdate plugin.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
- [Overview](#overview)
|
|
8
|
+
- [How Live Updates Work](#how-live-updates-work)
|
|
9
|
+
- [Setup Guide](#setup-guide)
|
|
10
|
+
- [Implementation Steps](#implementation-steps)
|
|
11
|
+
- [Update Server Setup](#update-server-setup)
|
|
12
|
+
- [Advanced Features](#advanced-features)
|
|
13
|
+
- [Best Practices](#best-practices)
|
|
14
|
+
- [Troubleshooting](#troubleshooting)
|
|
15
|
+
|
|
16
|
+
## Overview
|
|
17
|
+
|
|
18
|
+
Live Updates allow you to push JavaScript, HTML, CSS, and asset updates to your app without going through the app store review process. This enables:
|
|
19
|
+
|
|
20
|
+
- 🚀 Instant bug fixes
|
|
21
|
+
- ✨ Feature toggles
|
|
22
|
+
- 🎨 UI/UX improvements
|
|
23
|
+
- 📊 A/B testing
|
|
24
|
+
- 🔧 Quick configuration changes
|
|
25
|
+
|
|
26
|
+
### What Can Be Updated
|
|
27
|
+
|
|
28
|
+
✅ **Can Update:**
|
|
29
|
+
|
|
30
|
+
- JavaScript bundles
|
|
31
|
+
- HTML files
|
|
32
|
+
- CSS stylesheets
|
|
33
|
+
- Images and assets
|
|
34
|
+
- JSON configuration
|
|
35
|
+
- Web fonts
|
|
36
|
+
|
|
37
|
+
❌ **Cannot Update:**
|
|
38
|
+
|
|
39
|
+
- Native code (Java/Kotlin/Swift/Objective-C)
|
|
40
|
+
- Native plugins
|
|
41
|
+
- Platform-specific configurations
|
|
42
|
+
- App permissions
|
|
43
|
+
|
|
44
|
+
## How Live Updates Work
|
|
45
|
+
|
|
46
|
+
```mermaid
|
|
47
|
+
sequenceDiagram
|
|
48
|
+
participant App
|
|
49
|
+
participant Plugin
|
|
50
|
+
participant Server
|
|
51
|
+
participant Storage
|
|
52
|
+
|
|
53
|
+
App->>Plugin: checkForUpdate()
|
|
54
|
+
Plugin->>Server: GET /check?version=1.0.0
|
|
55
|
+
Server-->>Plugin: Update available (1.0.1)
|
|
56
|
+
Plugin->>App: Update found
|
|
57
|
+
App->>Plugin: downloadUpdate()
|
|
58
|
+
Plugin->>Server: Download bundle
|
|
59
|
+
Server-->>Plugin: Bundle data
|
|
60
|
+
Plugin->>Storage: Save & extract
|
|
61
|
+
Plugin->>App: Download complete
|
|
62
|
+
App->>Plugin: applyUpdate()
|
|
63
|
+
Plugin->>App: Restart required
|
|
64
|
+
App->>App: Reload with new bundle
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Setup Guide
|
|
68
|
+
|
|
69
|
+
### 1. Install the Plugin
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
npm install capacitor-native-update
|
|
73
|
+
npx cap sync
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### 2. Configure the Plugin
|
|
77
|
+
|
|
78
|
+
#### capacitor.config.json
|
|
79
|
+
|
|
80
|
+
```json
|
|
81
|
+
{
|
|
82
|
+
"appId": "com.example.app",
|
|
83
|
+
"appName": "My App",
|
|
84
|
+
"plugins": {
|
|
85
|
+
"CapacitorNativeUpdate": {
|
|
86
|
+
"updateUrl": "https://updates.yourdomain.com/api/v1",
|
|
87
|
+
"enabled": true,
|
|
88
|
+
"autoCheck": true,
|
|
89
|
+
"checkInterval": 3600,
|
|
90
|
+
"channel": "production",
|
|
91
|
+
"publicKey": "your-base64-public-key",
|
|
92
|
+
"enforceSignature": true,
|
|
93
|
+
"updateStrategy": "immediate",
|
|
94
|
+
"maxVersions": 3
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### 3. iOS Additional Setup
|
|
101
|
+
|
|
102
|
+
Add to `Info.plist`:
|
|
103
|
+
|
|
104
|
+
```xml
|
|
105
|
+
<key>CapacitorNativeUpdateEnabled</key>
|
|
106
|
+
<true/>
|
|
107
|
+
<key>CapacitorNativeUpdateURL</key>
|
|
108
|
+
<string>https://updates.yourdomain.com/api/v1</string>
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### 4. Android Additional Setup
|
|
112
|
+
|
|
113
|
+
Add to `AndroidManifest.xml`:
|
|
114
|
+
|
|
115
|
+
```xml
|
|
116
|
+
<uses-permission android:name="android.permission.INTERNET" />
|
|
117
|
+
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## Implementation Steps
|
|
121
|
+
|
|
122
|
+
### Step 1: Basic Implementation
|
|
123
|
+
|
|
124
|
+
```typescript
|
|
125
|
+
import { CapacitorNativeUpdate } from 'capacitor-native-update';
|
|
126
|
+
|
|
127
|
+
export class UpdateManager {
|
|
128
|
+
async checkAndUpdate() {
|
|
129
|
+
try {
|
|
130
|
+
// Check for updates
|
|
131
|
+
const { available, version } =
|
|
132
|
+
await CapacitorNativeUpdate.checkForUpdate();
|
|
133
|
+
|
|
134
|
+
if (available) {
|
|
135
|
+
console.log(`Update available: ${version}`);
|
|
136
|
+
|
|
137
|
+
// Download the update
|
|
138
|
+
const { success } = await CapacitorNativeUpdate.downloadUpdate({
|
|
139
|
+
onProgress: (progress) => {
|
|
140
|
+
console.log(`Download progress: ${progress.percent}%`);
|
|
141
|
+
},
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
if (success) {
|
|
145
|
+
// Apply the update
|
|
146
|
+
await CapacitorNativeUpdate.applyUpdate();
|
|
147
|
+
// App will restart automatically
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
} catch (error) {
|
|
151
|
+
console.error('Update failed:', error);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### Step 2: Advanced Implementation with UI
|
|
158
|
+
|
|
159
|
+
```typescript
|
|
160
|
+
import { CapacitorNativeUpdate } from 'capacitor-native-update';
|
|
161
|
+
import { AlertController, LoadingController } from '@ionic/angular';
|
|
162
|
+
|
|
163
|
+
export class UpdateService {
|
|
164
|
+
constructor(
|
|
165
|
+
private alertCtrl: AlertController,
|
|
166
|
+
private loadingCtrl: LoadingController
|
|
167
|
+
) {}
|
|
168
|
+
|
|
169
|
+
async checkForUpdates(silent = false) {
|
|
170
|
+
try {
|
|
171
|
+
const { available, version, mandatory, notes } =
|
|
172
|
+
await CapacitorNativeUpdate.checkForUpdate();
|
|
173
|
+
|
|
174
|
+
if (!available) {
|
|
175
|
+
if (!silent) {
|
|
176
|
+
await this.showAlert('No Updates', 'Your app is up to date!');
|
|
177
|
+
}
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// Show update dialog
|
|
182
|
+
const alert = await this.alertCtrl.create({
|
|
183
|
+
header: 'Update Available',
|
|
184
|
+
message: `Version ${version} is available.\n\n${notes || 'Bug fixes and improvements'}`,
|
|
185
|
+
buttons: [
|
|
186
|
+
{
|
|
187
|
+
text: mandatory ? 'Update Now' : 'Later',
|
|
188
|
+
role: 'cancel',
|
|
189
|
+
handler: () => {
|
|
190
|
+
if (mandatory) {
|
|
191
|
+
// Force update for mandatory updates
|
|
192
|
+
this.downloadAndApplyUpdate();
|
|
193
|
+
return false;
|
|
194
|
+
}
|
|
195
|
+
},
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
text: 'Update',
|
|
199
|
+
handler: () => {
|
|
200
|
+
this.downloadAndApplyUpdate();
|
|
201
|
+
},
|
|
202
|
+
},
|
|
203
|
+
],
|
|
204
|
+
backdropDismiss: !mandatory,
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
await alert.present();
|
|
208
|
+
} catch (error) {
|
|
209
|
+
console.error('Update check failed:', error);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
private async downloadAndApplyUpdate() {
|
|
214
|
+
const loading = await this.loadingCtrl.create({
|
|
215
|
+
message: 'Downloading update...',
|
|
216
|
+
backdropDismiss: false,
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
await loading.present();
|
|
220
|
+
|
|
221
|
+
try {
|
|
222
|
+
// Download with progress
|
|
223
|
+
await CapacitorNativeUpdate.downloadUpdate({
|
|
224
|
+
onProgress: (progress) => {
|
|
225
|
+
loading.message = `Downloading... ${Math.round(progress.percent)}%`;
|
|
226
|
+
},
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
loading.message = 'Applying update...';
|
|
230
|
+
|
|
231
|
+
// Apply the update
|
|
232
|
+
await CapacitorNativeUpdate.applyUpdate();
|
|
233
|
+
|
|
234
|
+
// The app will restart automatically
|
|
235
|
+
} catch (error) {
|
|
236
|
+
await loading.dismiss();
|
|
237
|
+
await this.showAlert('Update Failed', error.message);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
private async showAlert(header: string, message: string) {
|
|
242
|
+
const alert = await this.alertCtrl.create({
|
|
243
|
+
header,
|
|
244
|
+
message,
|
|
245
|
+
buttons: ['OK'],
|
|
246
|
+
});
|
|
247
|
+
await alert.present();
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
### Step 3: Auto-Update on App Start
|
|
253
|
+
|
|
254
|
+
```typescript
|
|
255
|
+
// app.component.ts
|
|
256
|
+
import { Component, OnInit } from '@angular/core';
|
|
257
|
+
import { Platform } from '@ionic/angular';
|
|
258
|
+
import { UpdateService } from './services/update.service';
|
|
259
|
+
|
|
260
|
+
@Component({
|
|
261
|
+
selector: 'app-root',
|
|
262
|
+
templateUrl: 'app.component.html',
|
|
263
|
+
})
|
|
264
|
+
export class AppComponent implements OnInit {
|
|
265
|
+
constructor(
|
|
266
|
+
private platform: Platform,
|
|
267
|
+
private updateService: UpdateService
|
|
268
|
+
) {}
|
|
269
|
+
|
|
270
|
+
async ngOnInit() {
|
|
271
|
+
await this.platform.ready();
|
|
272
|
+
|
|
273
|
+
// Check for updates on app start
|
|
274
|
+
await this.updateService.checkForUpdates(true);
|
|
275
|
+
|
|
276
|
+
// Set up periodic checks
|
|
277
|
+
setInterval(
|
|
278
|
+
() => {
|
|
279
|
+
this.updateService.checkForUpdates(true);
|
|
280
|
+
},
|
|
281
|
+
60 * 60 * 1000
|
|
282
|
+
); // Every hour
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
### Step 4: Update Strategies
|
|
288
|
+
|
|
289
|
+
```typescript
|
|
290
|
+
// Different update strategies
|
|
291
|
+
export class UpdateStrategies {
|
|
292
|
+
// Immediate update (default)
|
|
293
|
+
async immediateUpdate() {
|
|
294
|
+
const { available } = await CapacitorNativeUpdate.checkForUpdate();
|
|
295
|
+
if (available) {
|
|
296
|
+
await CapacitorNativeUpdate.downloadUpdate();
|
|
297
|
+
await CapacitorNativeUpdate.applyUpdate(); // Restarts immediately
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// Update on next restart
|
|
302
|
+
async updateOnRestart() {
|
|
303
|
+
const { available } = await CapacitorNativeUpdate.checkForUpdate();
|
|
304
|
+
if (available) {
|
|
305
|
+
await CapacitorNativeUpdate.downloadUpdate();
|
|
306
|
+
await CapacitorNativeUpdate.applyUpdate({
|
|
307
|
+
reloadStrategy: 'on-next-restart',
|
|
308
|
+
});
|
|
309
|
+
// Update will be applied next time app starts
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// Update with confirmation
|
|
314
|
+
async updateWithConfirmation() {
|
|
315
|
+
const { available } = await CapacitorNativeUpdate.checkForUpdate();
|
|
316
|
+
if (available) {
|
|
317
|
+
await CapacitorNativeUpdate.downloadUpdate();
|
|
318
|
+
|
|
319
|
+
// Show confirmation dialog
|
|
320
|
+
const confirmed = await this.showUpdateReadyDialog();
|
|
321
|
+
if (confirmed) {
|
|
322
|
+
await CapacitorNativeUpdate.applyUpdate();
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
## Update Server Setup
|
|
330
|
+
|
|
331
|
+
### Option 1: Use Our Example Server
|
|
332
|
+
|
|
333
|
+
```bash
|
|
334
|
+
cd server-example
|
|
335
|
+
npm install
|
|
336
|
+
npm start
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
### Option 2: Implement Your Own
|
|
340
|
+
|
|
341
|
+
#### Bundle Structure
|
|
342
|
+
|
|
343
|
+
```
|
|
344
|
+
bundle-1.0.1.zip
|
|
345
|
+
├── www/
|
|
346
|
+
│ ├── index.html
|
|
347
|
+
│ ├── js/
|
|
348
|
+
│ │ └── app.bundle.js
|
|
349
|
+
│ ├── css/
|
|
350
|
+
│ │ └── styles.css
|
|
351
|
+
│ └── assets/
|
|
352
|
+
│ └── images/
|
|
353
|
+
└── manifest.json
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
#### manifest.json
|
|
357
|
+
|
|
358
|
+
```json
|
|
359
|
+
{
|
|
360
|
+
"version": "1.0.1",
|
|
361
|
+
"minNativeVersion": "1.0.0",
|
|
362
|
+
"timestamp": "2023-12-01T00:00:00Z",
|
|
363
|
+
"files": ["www/index.html", "www/js/app.bundle.js", "www/css/styles.css"]
|
|
364
|
+
}
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
#### Server API Requirements
|
|
368
|
+
|
|
369
|
+
**Check Endpoint:**
|
|
370
|
+
|
|
371
|
+
```http
|
|
372
|
+
GET /api/v1/check?version=1.0.0&channel=production&appId=com.example.app
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
Response:
|
|
376
|
+
|
|
377
|
+
```json
|
|
378
|
+
{
|
|
379
|
+
"available": true,
|
|
380
|
+
"version": "1.0.1",
|
|
381
|
+
"url": "https://updates.example.com/bundles/1.0.1.zip",
|
|
382
|
+
"mandatory": false,
|
|
383
|
+
"notes": "Bug fixes and performance improvements",
|
|
384
|
+
"size": 2048576,
|
|
385
|
+
"checksum": "sha256:abc123...",
|
|
386
|
+
"signature": "base64signature...",
|
|
387
|
+
"minNativeVersion": "1.0.0"
|
|
388
|
+
}
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
### Creating Update Bundles
|
|
392
|
+
|
|
393
|
+
```bash
|
|
394
|
+
# 1. Build your web app
|
|
395
|
+
npm run build
|
|
396
|
+
|
|
397
|
+
# 2. Create bundle
|
|
398
|
+
cd dist
|
|
399
|
+
zip -r ../bundle-1.0.1.zip www/
|
|
400
|
+
|
|
401
|
+
# 3. Sign the bundle (optional but recommended)
|
|
402
|
+
cd ..
|
|
403
|
+
node server-example/bundle-signer.js sign bundle-1.0.1.zip
|
|
404
|
+
|
|
405
|
+
# 4. Upload to server
|
|
406
|
+
curl -X POST https://updates.example.com/api/v1/bundles \
|
|
407
|
+
-H "Authorization: Bearer $ADMIN_TOKEN" \
|
|
408
|
+
-F "file=@bundle-1.0.1.zip" \
|
|
409
|
+
-F "version=1.0.1" \
|
|
410
|
+
-F "channel=production" \
|
|
411
|
+
-F "notes=Bug fixes"
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
## Advanced Features
|
|
415
|
+
|
|
416
|
+
### 1. Update Channels
|
|
417
|
+
|
|
418
|
+
```typescript
|
|
419
|
+
// Development channel for testing
|
|
420
|
+
await CapacitorNativeUpdate.setChannel({ channel: 'development' });
|
|
421
|
+
|
|
422
|
+
// Production channel for users
|
|
423
|
+
await CapacitorNativeUpdate.setChannel({ channel: 'production' });
|
|
424
|
+
|
|
425
|
+
// Beta channel for early adopters
|
|
426
|
+
await CapacitorNativeUpdate.setChannel({ channel: 'beta' });
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
### 2. Delta Updates
|
|
430
|
+
|
|
431
|
+
```typescript
|
|
432
|
+
// Enable delta updates to reduce download size
|
|
433
|
+
await CapacitorNativeUpdate.configureDeltaUpdates({
|
|
434
|
+
enabled: true,
|
|
435
|
+
threshold: 0.3, // Use delta if size < 30% of full bundle
|
|
436
|
+
});
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
### 3. Rollback Support
|
|
440
|
+
|
|
441
|
+
```typescript
|
|
442
|
+
// List available versions
|
|
443
|
+
const { versions } = await CapacitorNativeUpdate.getVersions();
|
|
444
|
+
|
|
445
|
+
// Rollback to previous version
|
|
446
|
+
if (versions.length > 1) {
|
|
447
|
+
await CapacitorNativeUpdate.rollback();
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
// Rollback to specific version
|
|
451
|
+
await CapacitorNativeUpdate.switchVersion({
|
|
452
|
+
version: '1.0.0',
|
|
453
|
+
});
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
### 4. Update Metrics
|
|
457
|
+
|
|
458
|
+
```typescript
|
|
459
|
+
// Track update success
|
|
460
|
+
await CapacitorNativeUpdate.reportUpdateSuccess({
|
|
461
|
+
version: '1.0.1',
|
|
462
|
+
duration: 5000,
|
|
463
|
+
});
|
|
464
|
+
|
|
465
|
+
// Track update failure
|
|
466
|
+
await CapacitorNativeUpdate.reportUpdateFailure({
|
|
467
|
+
version: '1.0.1',
|
|
468
|
+
error: 'DOWNLOAD_FAILED',
|
|
469
|
+
details: 'Network timeout',
|
|
470
|
+
});
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
### 5. Custom Update UI
|
|
474
|
+
|
|
475
|
+
```typescript
|
|
476
|
+
// Disable auto-check
|
|
477
|
+
await CapacitorNativeUpdate.configure({
|
|
478
|
+
autoCheck: false,
|
|
479
|
+
});
|
|
480
|
+
|
|
481
|
+
// Implement custom UI
|
|
482
|
+
class CustomUpdateUI {
|
|
483
|
+
async showUpdateFlow() {
|
|
484
|
+
// Custom check
|
|
485
|
+
const update = await CapacitorNativeUpdate.checkForUpdate();
|
|
486
|
+
|
|
487
|
+
if (update.available) {
|
|
488
|
+
// Show custom UI
|
|
489
|
+
const modal = await this.modalCtrl.create({
|
|
490
|
+
component: UpdateModalComponent,
|
|
491
|
+
componentProps: { update },
|
|
492
|
+
});
|
|
493
|
+
|
|
494
|
+
await modal.present();
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
```
|
|
499
|
+
|
|
500
|
+
## Best Practices
|
|
501
|
+
|
|
502
|
+
### 1. Version Management
|
|
503
|
+
|
|
504
|
+
```typescript
|
|
505
|
+
// Semantic versioning
|
|
506
|
+
const versions = {
|
|
507
|
+
major: '2.0.0', // Breaking changes
|
|
508
|
+
minor: '1.1.0', // New features
|
|
509
|
+
patch: '1.0.1', // Bug fixes
|
|
510
|
+
};
|
|
511
|
+
|
|
512
|
+
// Skip versions if needed
|
|
513
|
+
const skipVersions = ['1.0.2', '1.0.3']; // Known bad versions
|
|
514
|
+
```
|
|
515
|
+
|
|
516
|
+
### 2. Error Handling
|
|
517
|
+
|
|
518
|
+
```typescript
|
|
519
|
+
class RobustUpdateManager {
|
|
520
|
+
async safeUpdate() {
|
|
521
|
+
try {
|
|
522
|
+
await CapacitorNativeUpdate.checkForUpdate();
|
|
523
|
+
} catch (error) {
|
|
524
|
+
if (error.code === 'NETWORK_ERROR') {
|
|
525
|
+
// Retry with exponential backoff
|
|
526
|
+
await this.retryWithBackoff();
|
|
527
|
+
} else if (error.code === 'INVALID_SIGNATURE') {
|
|
528
|
+
// Security issue - don't apply
|
|
529
|
+
await this.reportSecurityIssue(error);
|
|
530
|
+
} else {
|
|
531
|
+
// Generic error handling
|
|
532
|
+
console.error('Update failed:', error);
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
```
|
|
538
|
+
|
|
539
|
+
### 3. Testing Updates
|
|
540
|
+
|
|
541
|
+
```typescript
|
|
542
|
+
// Test in development
|
|
543
|
+
if (environment.development) {
|
|
544
|
+
// Force check against staging server
|
|
545
|
+
await CapacitorNativeUpdate.configure({
|
|
546
|
+
updateUrl: 'https://staging-updates.yourdomain.com',
|
|
547
|
+
channel: 'development',
|
|
548
|
+
});
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
// A/B testing
|
|
552
|
+
const testGroup = user.id % 2 === 0 ? 'A' : 'B';
|
|
553
|
+
await CapacitorNativeUpdate.setChannel({
|
|
554
|
+
channel: `production-${testGroup}`,
|
|
555
|
+
});
|
|
556
|
+
```
|
|
557
|
+
|
|
558
|
+
### 4. Performance Optimization
|
|
559
|
+
|
|
560
|
+
```typescript
|
|
561
|
+
// Download during off-peak hours
|
|
562
|
+
const now = new Date().getHours();
|
|
563
|
+
if (now >= 2 && now <= 6) {
|
|
564
|
+
await CapacitorNativeUpdate.downloadUpdate({
|
|
565
|
+
priority: 'low',
|
|
566
|
+
});
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
// Pause/resume downloads
|
|
570
|
+
const downloadId = await CapacitorNativeUpdate.startDownload();
|
|
571
|
+
await CapacitorNativeUpdate.pauseDownload({ id: downloadId });
|
|
572
|
+
await CapacitorNativeUpdate.resumeDownload({ id: downloadId });
|
|
573
|
+
```
|
|
574
|
+
|
|
575
|
+
## Troubleshooting
|
|
576
|
+
|
|
577
|
+
### Common Issues
|
|
578
|
+
|
|
579
|
+
1. **Update not applying**
|
|
580
|
+
|
|
581
|
+
```typescript
|
|
582
|
+
// Check if update was downloaded
|
|
583
|
+
const { ready } = await CapacitorNativeUpdate.isUpdateReady();
|
|
584
|
+
if (ready) {
|
|
585
|
+
// Force apply
|
|
586
|
+
await CapacitorNativeUpdate.applyUpdate({ force: true });
|
|
587
|
+
}
|
|
588
|
+
```
|
|
589
|
+
|
|
590
|
+
2. **Signature verification fails**
|
|
591
|
+
|
|
592
|
+
```typescript
|
|
593
|
+
// Verify public key configuration
|
|
594
|
+
const config = await CapacitorNativeUpdate.getConfiguration();
|
|
595
|
+
console.log('Public key:', config.publicKey);
|
|
596
|
+
```
|
|
597
|
+
|
|
598
|
+
3. **Storage issues**
|
|
599
|
+
```typescript
|
|
600
|
+
// Clear old versions
|
|
601
|
+
await CapacitorNativeUpdate.cleanup({
|
|
602
|
+
keepVersions: 1,
|
|
603
|
+
});
|
|
604
|
+
```
|
|
605
|
+
|
|
606
|
+
### Debug Mode
|
|
607
|
+
|
|
608
|
+
```typescript
|
|
609
|
+
// Enable debug logging
|
|
610
|
+
await CapacitorNativeUpdate.setDebugMode({ enabled: true });
|
|
611
|
+
|
|
612
|
+
// Monitor update events
|
|
613
|
+
CapacitorNativeUpdate.addListener('updateDownloadProgress', (progress) => {
|
|
614
|
+
console.log('Download progress:', progress);
|
|
615
|
+
});
|
|
616
|
+
|
|
617
|
+
CapacitorNativeUpdate.addListener('updateStateChange', (state) => {
|
|
618
|
+
console.log('Update state:', state);
|
|
619
|
+
});
|
|
620
|
+
```
|
|
621
|
+
|
|
622
|
+
### Health Checks
|
|
623
|
+
|
|
624
|
+
```typescript
|
|
625
|
+
// Verify update system health
|
|
626
|
+
const health = await CapacitorNativeUpdate.getHealth();
|
|
627
|
+
console.log('Update system health:', {
|
|
628
|
+
enabled: health.enabled,
|
|
629
|
+
lastCheck: health.lastCheck,
|
|
630
|
+
lastUpdate: health.lastUpdate,
|
|
631
|
+
currentVersion: health.currentVersion,
|
|
632
|
+
availableSpace: health.availableSpace,
|
|
633
|
+
});
|
|
634
|
+
```
|
|
635
|
+
|
|
636
|
+
## Security Considerations
|
|
637
|
+
|
|
638
|
+
1. **Always use HTTPS** for update servers
|
|
639
|
+
2. **Implement bundle signing** to prevent tampering
|
|
640
|
+
3. **Validate checksums** before applying updates
|
|
641
|
+
4. **Use certificate pinning** for extra security
|
|
642
|
+
5. **Implement rollback** mechanisms for safety
|
|
643
|
+
6. **Monitor update metrics** to detect issues
|
|
644
|
+
|
|
645
|
+
## Next Steps
|
|
646
|
+
|
|
647
|
+
- Read the [Native App Updates Guide](./NATIVE_UPDATES_GUIDE.md)
|
|
648
|
+
- Learn about [App Review Integration](./APP_REVIEW_GUIDE.md)
|
|
649
|
+
- Check out [Security Best Practices](./SECURITY.md)
|
|
650
|
+
- See [Bundle Signing Documentation](./BUNDLE_SIGNING.md)
|