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,606 @@
|
|
|
1
|
+
# Quick Start Guide
|
|
2
|
+
|
|
3
|
+
Get up and running with Capacitor Native Update in 5 minutes! This guide covers all three main features:
|
|
4
|
+
|
|
5
|
+
1. **Live Updates (OTA)** - Push JavaScript/CSS updates instantly
|
|
6
|
+
2. **Native App Updates** - Check and install app store updates
|
|
7
|
+
3. **App Reviews** - Request in-app ratings and reviews
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
# Install the plugin
|
|
13
|
+
npm install capacitor-native-update
|
|
14
|
+
|
|
15
|
+
# Sync with native projects
|
|
16
|
+
npx cap sync
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Basic Setup
|
|
20
|
+
|
|
21
|
+
### 1. Configure the Plugin
|
|
22
|
+
|
|
23
|
+
**capacitor.config.json**:
|
|
24
|
+
|
|
25
|
+
```json
|
|
26
|
+
{
|
|
27
|
+
"appId": "com.example.app",
|
|
28
|
+
"appName": "MyApp",
|
|
29
|
+
"plugins": {
|
|
30
|
+
"CapacitorNativeUpdate": {
|
|
31
|
+
"updateUrl": "https://updates.example.com/api/v1",
|
|
32
|
+
"autoCheck": true,
|
|
33
|
+
"appStoreId": "123456789"
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### 2. Import and Initialize
|
|
40
|
+
|
|
41
|
+
```typescript
|
|
42
|
+
import { CapacitorNativeUpdate } from 'capacitor-native-update';
|
|
43
|
+
|
|
44
|
+
// Initialize on app start
|
|
45
|
+
export class App {
|
|
46
|
+
async ngOnInit() {
|
|
47
|
+
await this.initializeUpdates();
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
async initializeUpdates() {
|
|
51
|
+
// Check for all types of updates
|
|
52
|
+
await this.checkLiveUpdates();
|
|
53
|
+
await this.checkNativeUpdates();
|
|
54
|
+
|
|
55
|
+
// Set up review prompt for later
|
|
56
|
+
this.scheduleReviewPrompt();
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Feature 1: Live Updates (OTA)
|
|
62
|
+
|
|
63
|
+
Push updates without app store review!
|
|
64
|
+
|
|
65
|
+
### Basic Implementation
|
|
66
|
+
|
|
67
|
+
```typescript
|
|
68
|
+
import { CapacitorNativeUpdate } from 'capacitor-native-update';
|
|
69
|
+
|
|
70
|
+
export class LiveUpdateService {
|
|
71
|
+
async checkAndApplyUpdates() {
|
|
72
|
+
try {
|
|
73
|
+
// 1. Check for updates
|
|
74
|
+
const { available, version } =
|
|
75
|
+
await CapacitorNativeUpdate.checkForUpdate();
|
|
76
|
+
|
|
77
|
+
if (!available) {
|
|
78
|
+
console.log('No updates available');
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
console.log(`Update ${version} available!`);
|
|
83
|
+
|
|
84
|
+
// 2. Download the update
|
|
85
|
+
await CapacitorNativeUpdate.downloadUpdate({
|
|
86
|
+
onProgress: (progress) => {
|
|
87
|
+
console.log(`Download: ${progress.percent}%`);
|
|
88
|
+
},
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
// 3. Apply the update (app will restart)
|
|
92
|
+
await CapacitorNativeUpdate.applyUpdate();
|
|
93
|
+
} catch (error) {
|
|
94
|
+
console.error('Update failed:', error);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### With User Interface
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
export class UpdateUIService {
|
|
104
|
+
constructor(
|
|
105
|
+
private alertController: AlertController,
|
|
106
|
+
private loadingController: LoadingController
|
|
107
|
+
) {}
|
|
108
|
+
|
|
109
|
+
async checkForUpdatesWithUI() {
|
|
110
|
+
const { available, version, notes } =
|
|
111
|
+
await CapacitorNativeUpdate.checkForUpdate();
|
|
112
|
+
|
|
113
|
+
if (!available) return;
|
|
114
|
+
|
|
115
|
+
// Show update dialog
|
|
116
|
+
const alert = await this.alertController.create({
|
|
117
|
+
header: 'Update Available',
|
|
118
|
+
message: `Version ${version} is ready!\n\n${notes || 'Bug fixes and improvements'}`,
|
|
119
|
+
buttons: [
|
|
120
|
+
{ text: 'Later', role: 'cancel' },
|
|
121
|
+
{
|
|
122
|
+
text: 'Update Now',
|
|
123
|
+
handler: () => this.downloadAndInstall(),
|
|
124
|
+
},
|
|
125
|
+
],
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
await alert.present();
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
private async downloadAndInstall() {
|
|
132
|
+
const loading = await this.loadingController.create({
|
|
133
|
+
message: 'Downloading update...',
|
|
134
|
+
});
|
|
135
|
+
await loading.present();
|
|
136
|
+
|
|
137
|
+
try {
|
|
138
|
+
await CapacitorNativeUpdate.downloadUpdate({
|
|
139
|
+
onProgress: (progress) => {
|
|
140
|
+
loading.message = `Downloading: ${Math.round(progress.percent)}%`;
|
|
141
|
+
},
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
loading.message = 'Installing...';
|
|
145
|
+
await CapacitorNativeUpdate.applyUpdate();
|
|
146
|
+
} catch (error) {
|
|
147
|
+
await loading.dismiss();
|
|
148
|
+
// Show error
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### Setting Up Update Server
|
|
155
|
+
|
|
156
|
+
Use our example server or implement your own:
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
# Using example server
|
|
160
|
+
cd server-example
|
|
161
|
+
npm install
|
|
162
|
+
npm start
|
|
163
|
+
|
|
164
|
+
# Upload a bundle
|
|
165
|
+
curl -X POST http://localhost:3000/api/v1/bundles \
|
|
166
|
+
-H "Authorization: Bearer your-token" \
|
|
167
|
+
-F "file=@bundle.zip" \
|
|
168
|
+
-F "version=1.0.1" \
|
|
169
|
+
-F "channel=production"
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
## Feature 2: Native App Updates
|
|
173
|
+
|
|
174
|
+
Check for app store updates and install them!
|
|
175
|
+
|
|
176
|
+
### Basic Implementation
|
|
177
|
+
|
|
178
|
+
```typescript
|
|
179
|
+
export class NativeUpdateService {
|
|
180
|
+
async checkForAppStoreUpdates() {
|
|
181
|
+
try {
|
|
182
|
+
const result = await CapacitorNativeUpdate.checkAppUpdate();
|
|
183
|
+
|
|
184
|
+
if (!result.updateAvailable) {
|
|
185
|
+
console.log('App is up to date');
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Handle based on platform
|
|
190
|
+
if (Capacitor.getPlatform() === 'android') {
|
|
191
|
+
await this.handleAndroidUpdate(result);
|
|
192
|
+
} else if (Capacitor.getPlatform() === 'ios') {
|
|
193
|
+
await this.handleiOSUpdate(result);
|
|
194
|
+
}
|
|
195
|
+
} catch (error) {
|
|
196
|
+
console.error('Native update check failed:', error);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
private async handleAndroidUpdate(result: any) {
|
|
201
|
+
if (result.immediateUpdateAllowed) {
|
|
202
|
+
// Critical update - must install
|
|
203
|
+
await CapacitorNativeUpdate.startImmediateUpdate();
|
|
204
|
+
} else {
|
|
205
|
+
// Optional update - download in background
|
|
206
|
+
await CapacitorNativeUpdate.startFlexibleUpdate();
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
private async handleiOSUpdate(result: any) {
|
|
211
|
+
// iOS can only redirect to App Store
|
|
212
|
+
const alert = await this.alertController.create({
|
|
213
|
+
header: 'Update Available',
|
|
214
|
+
message: `Version ${result.availableVersion} is available on the App Store`,
|
|
215
|
+
buttons: [
|
|
216
|
+
{ text: 'Later', role: 'cancel' },
|
|
217
|
+
{
|
|
218
|
+
text: 'Update',
|
|
219
|
+
handler: () => CapacitorNativeUpdate.openAppStore(),
|
|
220
|
+
},
|
|
221
|
+
],
|
|
222
|
+
});
|
|
223
|
+
await alert.present();
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
### With Progress Tracking (Android)
|
|
229
|
+
|
|
230
|
+
```typescript
|
|
231
|
+
export class AndroidUpdateProgress {
|
|
232
|
+
downloadProgress = 0;
|
|
233
|
+
|
|
234
|
+
async startFlexibleUpdate() {
|
|
235
|
+
// Start download
|
|
236
|
+
await CapacitorNativeUpdate.startFlexibleUpdate();
|
|
237
|
+
|
|
238
|
+
// Track progress
|
|
239
|
+
CapacitorNativeUpdate.addListener(
|
|
240
|
+
'onAppUpdateDownloadProgress',
|
|
241
|
+
(progress) => {
|
|
242
|
+
this.downloadProgress = Math.round(
|
|
243
|
+
(progress.bytesDownloaded / progress.totalBytesToDownload) * 100
|
|
244
|
+
);
|
|
245
|
+
}
|
|
246
|
+
);
|
|
247
|
+
|
|
248
|
+
// Handle completion
|
|
249
|
+
CapacitorNativeUpdate.addListener('onAppUpdateDownloaded', async () => {
|
|
250
|
+
const alert = await this.alertController.create({
|
|
251
|
+
header: 'Update Ready',
|
|
252
|
+
message: 'Update has been downloaded. Install now?',
|
|
253
|
+
buttons: [
|
|
254
|
+
{ text: 'Later' },
|
|
255
|
+
{
|
|
256
|
+
text: 'Install',
|
|
257
|
+
handler: () => CapacitorNativeUpdate.completeFlexibleUpdate(),
|
|
258
|
+
},
|
|
259
|
+
],
|
|
260
|
+
});
|
|
261
|
+
await alert.present();
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
## Feature 3: App Reviews
|
|
268
|
+
|
|
269
|
+
Request ratings without users leaving your app!
|
|
270
|
+
|
|
271
|
+
### Basic Implementation
|
|
272
|
+
|
|
273
|
+
```typescript
|
|
274
|
+
export class AppReviewService {
|
|
275
|
+
async requestReview() {
|
|
276
|
+
try {
|
|
277
|
+
const result = await CapacitorNativeUpdate.requestReview();
|
|
278
|
+
|
|
279
|
+
if (result.displayed) {
|
|
280
|
+
console.log('Review prompt shown');
|
|
281
|
+
// Track analytics
|
|
282
|
+
}
|
|
283
|
+
} catch (error) {
|
|
284
|
+
console.error('Review request failed:', error);
|
|
285
|
+
// Fallback to external review
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
### Smart Review Prompts
|
|
292
|
+
|
|
293
|
+
Only ask at the right moments:
|
|
294
|
+
|
|
295
|
+
```typescript
|
|
296
|
+
export class SmartReviewService {
|
|
297
|
+
private readonly MIN_SESSIONS = 3;
|
|
298
|
+
private readonly MIN_DAYS_INSTALLED = 3;
|
|
299
|
+
|
|
300
|
+
async checkAndRequestReview() {
|
|
301
|
+
// Don't ask too early
|
|
302
|
+
if (!(await this.isGoodTimeToAsk())) {
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// Two-step approach
|
|
307
|
+
const enjoying = await this.askIfEnjoying();
|
|
308
|
+
|
|
309
|
+
if (enjoying) {
|
|
310
|
+
await CapacitorNativeUpdate.requestReview();
|
|
311
|
+
} else {
|
|
312
|
+
await this.askForFeedback();
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
private async isGoodTimeToAsk(): Promise<boolean> {
|
|
317
|
+
const sessions = await this.getSessionCount();
|
|
318
|
+
const daysSinceInstall = await this.getDaysSinceInstall();
|
|
319
|
+
|
|
320
|
+
return (
|
|
321
|
+
sessions >= this.MIN_SESSIONS &&
|
|
322
|
+
daysSinceInstall >= this.MIN_DAYS_INSTALLED
|
|
323
|
+
);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
private async askIfEnjoying(): Promise<boolean> {
|
|
327
|
+
return new Promise((resolve) => {
|
|
328
|
+
const alert = this.alertController.create({
|
|
329
|
+
header: 'Enjoying MyApp?',
|
|
330
|
+
buttons: [
|
|
331
|
+
{
|
|
332
|
+
text: 'Not really',
|
|
333
|
+
handler: () => resolve(false),
|
|
334
|
+
},
|
|
335
|
+
{
|
|
336
|
+
text: 'Yes!',
|
|
337
|
+
handler: () => resolve(true),
|
|
338
|
+
},
|
|
339
|
+
],
|
|
340
|
+
});
|
|
341
|
+
alert.present();
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
### Review Triggers
|
|
348
|
+
|
|
349
|
+
Call review prompts at optimal moments:
|
|
350
|
+
|
|
351
|
+
```typescript
|
|
352
|
+
export class ReviewTriggers {
|
|
353
|
+
constructor(private reviewService: SmartReviewService) {}
|
|
354
|
+
|
|
355
|
+
// After completing important task
|
|
356
|
+
async onTaskCompleted() {
|
|
357
|
+
const taskCount = await this.getCompletedTasks();
|
|
358
|
+
|
|
359
|
+
// Every 5 tasks
|
|
360
|
+
if (taskCount % 5 === 0) {
|
|
361
|
+
setTimeout(() => {
|
|
362
|
+
this.reviewService.checkAndRequestReview();
|
|
363
|
+
}, 2000);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
// After positive interaction
|
|
368
|
+
async onPositiveEvent() {
|
|
369
|
+
await this.reviewService.checkAndRequestReview();
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
// On app launch (with conditions)
|
|
373
|
+
async onAppLaunch() {
|
|
374
|
+
const lastPrompt = await this.getLastPromptDate();
|
|
375
|
+
const daysSince = this.daysSince(lastPrompt);
|
|
376
|
+
|
|
377
|
+
// Max once per month
|
|
378
|
+
if (daysSince >= 30) {
|
|
379
|
+
await this.reviewService.checkAndRequestReview();
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
## Complete Example
|
|
386
|
+
|
|
387
|
+
Here's everything working together:
|
|
388
|
+
|
|
389
|
+
```typescript
|
|
390
|
+
import { Component, OnInit } from '@angular/core';
|
|
391
|
+
import { CapacitorNativeUpdate } from 'capacitor-native-update';
|
|
392
|
+
import { Capacitor } from '@capacitor/core';
|
|
393
|
+
|
|
394
|
+
@Component({
|
|
395
|
+
selector: 'app-root',
|
|
396
|
+
templateUrl: 'app.component.html',
|
|
397
|
+
})
|
|
398
|
+
export class AppComponent implements OnInit {
|
|
399
|
+
constructor(
|
|
400
|
+
private platform: Platform,
|
|
401
|
+
private alertCtrl: AlertController
|
|
402
|
+
) {}
|
|
403
|
+
|
|
404
|
+
async ngOnInit() {
|
|
405
|
+
await this.platform.ready();
|
|
406
|
+
|
|
407
|
+
// Initialize all update features
|
|
408
|
+
await this.initializeUpdates();
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
async initializeUpdates() {
|
|
412
|
+
// 1. Check for live updates on startup
|
|
413
|
+
this.checkLiveUpdates();
|
|
414
|
+
|
|
415
|
+
// 2. Check for native updates periodically
|
|
416
|
+
this.scheduleNativeUpdateCheck();
|
|
417
|
+
|
|
418
|
+
// 3. Set up smart review prompts
|
|
419
|
+
this.initializeReviewPrompts();
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
// Live Updates
|
|
423
|
+
private async checkLiveUpdates() {
|
|
424
|
+
try {
|
|
425
|
+
const { available } = await CapacitorNativeUpdate.checkForUpdate();
|
|
426
|
+
|
|
427
|
+
if (available) {
|
|
428
|
+
// Auto-download in background
|
|
429
|
+
await CapacitorNativeUpdate.downloadUpdate();
|
|
430
|
+
|
|
431
|
+
// Notify user
|
|
432
|
+
const toast = await this.toastCtrl.create({
|
|
433
|
+
message: 'Update ready! Restart to apply.',
|
|
434
|
+
duration: 5000,
|
|
435
|
+
buttons: [
|
|
436
|
+
{
|
|
437
|
+
text: 'Restart',
|
|
438
|
+
handler: () => CapacitorNativeUpdate.applyUpdate(),
|
|
439
|
+
},
|
|
440
|
+
],
|
|
441
|
+
});
|
|
442
|
+
await toast.present();
|
|
443
|
+
}
|
|
444
|
+
} catch (error) {
|
|
445
|
+
console.error('Live update check failed:', error);
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
// Native Updates
|
|
450
|
+
private scheduleNativeUpdateCheck() {
|
|
451
|
+
// Check immediately
|
|
452
|
+
this.checkNativeUpdates();
|
|
453
|
+
|
|
454
|
+
// Then check daily
|
|
455
|
+
setInterval(
|
|
456
|
+
() => {
|
|
457
|
+
this.checkNativeUpdates();
|
|
458
|
+
},
|
|
459
|
+
24 * 60 * 60 * 1000
|
|
460
|
+
);
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
private async checkNativeUpdates() {
|
|
464
|
+
try {
|
|
465
|
+
const result = await CapacitorNativeUpdate.checkAppUpdate();
|
|
466
|
+
|
|
467
|
+
if (result.updateAvailable && result.flexibleUpdateAllowed) {
|
|
468
|
+
// Start background download for Android
|
|
469
|
+
if (Capacitor.getPlatform() === 'android') {
|
|
470
|
+
await CapacitorNativeUpdate.startFlexibleUpdate();
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
} catch (error) {
|
|
474
|
+
console.error('Native update check failed:', error);
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
// App Reviews
|
|
479
|
+
private initializeReviewPrompts() {
|
|
480
|
+
// Track positive events
|
|
481
|
+
document.addEventListener('task-completed', () => {
|
|
482
|
+
this.maybeRequestReview();
|
|
483
|
+
});
|
|
484
|
+
|
|
485
|
+
// Check on app foreground
|
|
486
|
+
document.addEventListener('resume', () => {
|
|
487
|
+
this.maybeRequestReview();
|
|
488
|
+
});
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
private async maybeRequestReview() {
|
|
492
|
+
const canAsk = await this.canAskForReview();
|
|
493
|
+
|
|
494
|
+
if (canAsk) {
|
|
495
|
+
await CapacitorNativeUpdate.requestReview();
|
|
496
|
+
await this.markReviewRequested();
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
private async canAskForReview(): Promise<boolean> {
|
|
501
|
+
// Your conditions here
|
|
502
|
+
const lastAsked = await this.getLastReviewDate();
|
|
503
|
+
const daysSince = this.daysSince(lastAsked);
|
|
504
|
+
|
|
505
|
+
return daysSince > 30; // Once per month max
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
```
|
|
509
|
+
|
|
510
|
+
## Testing Your Implementation
|
|
511
|
+
|
|
512
|
+
### 1. Test Live Updates
|
|
513
|
+
|
|
514
|
+
```bash
|
|
515
|
+
# Build your web app
|
|
516
|
+
npm run build
|
|
517
|
+
|
|
518
|
+
# Create update bundle
|
|
519
|
+
cd www && zip -r ../update-1.0.1.zip . && cd ..
|
|
520
|
+
|
|
521
|
+
# Upload to test server
|
|
522
|
+
curl -X POST http://localhost:3000/api/v1/bundles \
|
|
523
|
+
-H "Authorization: Bearer test-token" \
|
|
524
|
+
-F "file=@update-1.0.1.zip" \
|
|
525
|
+
-F "version=1.0.1"
|
|
526
|
+
|
|
527
|
+
# Test in app
|
|
528
|
+
```
|
|
529
|
+
|
|
530
|
+
### 2. Test Native Updates
|
|
531
|
+
|
|
532
|
+
**Android:**
|
|
533
|
+
|
|
534
|
+
- Upload APK to Internal Test Track
|
|
535
|
+
- Install older version
|
|
536
|
+
- Open app to trigger update
|
|
537
|
+
|
|
538
|
+
**iOS:**
|
|
539
|
+
|
|
540
|
+
- Use TestFlight
|
|
541
|
+
- Install older version
|
|
542
|
+
- Check for updates in app
|
|
543
|
+
|
|
544
|
+
### 3. Test App Reviews
|
|
545
|
+
|
|
546
|
+
```typescript
|
|
547
|
+
// Enable debug mode
|
|
548
|
+
await CapacitorNativeUpdate.setReviewDebugMode({ enabled: true });
|
|
549
|
+
|
|
550
|
+
// Force show review (debug only)
|
|
551
|
+
await CapacitorNativeUpdate.requestReview({ force: true });
|
|
552
|
+
```
|
|
553
|
+
|
|
554
|
+
## What's Next?
|
|
555
|
+
|
|
556
|
+
Now that you have the basics working:
|
|
557
|
+
|
|
558
|
+
1. **Production Setup**:
|
|
559
|
+
- Set up a proper update server
|
|
560
|
+
- Implement bundle signing
|
|
561
|
+
- Configure update channels
|
|
562
|
+
|
|
563
|
+
2. **Advanced Features**:
|
|
564
|
+
- Delta updates for smaller downloads
|
|
565
|
+
- A/B testing different update strategies
|
|
566
|
+
- Rollback capabilities
|
|
567
|
+
|
|
568
|
+
3. **Deep Dive**:
|
|
569
|
+
- [Live Updates Guide](./LIVE_UPDATES_GUIDE.md) - Complete OTA implementation
|
|
570
|
+
- [Native Updates Guide](./NATIVE_UPDATES_GUIDE.md) - Platform-specific details
|
|
571
|
+
- [App Review Guide](./APP_REVIEW_GUIDE.md) - Maximize review rates
|
|
572
|
+
- [Security Guide](./SECURITY.md) - Best practices
|
|
573
|
+
- [API Reference](../API.md) - All methods and options
|
|
574
|
+
|
|
575
|
+
## Troubleshooting
|
|
576
|
+
|
|
577
|
+
### Live Updates Not Working?
|
|
578
|
+
|
|
579
|
+
```typescript
|
|
580
|
+
// Enable debug logging
|
|
581
|
+
await CapacitorNativeUpdate.setDebugMode({ enabled: true });
|
|
582
|
+
|
|
583
|
+
// Check configuration
|
|
584
|
+
const config = await CapacitorNativeUpdate.getConfiguration();
|
|
585
|
+
console.log('Update URL:', config.updateUrl);
|
|
586
|
+
```
|
|
587
|
+
|
|
588
|
+
### Native Updates Not Detected?
|
|
589
|
+
|
|
590
|
+
- Ensure app is published on store
|
|
591
|
+
- Check version numbers are correct
|
|
592
|
+
- Verify package name matches
|
|
593
|
+
|
|
594
|
+
### Reviews Not Showing?
|
|
595
|
+
|
|
596
|
+
- iOS: Limited to 3 times per year by system
|
|
597
|
+
- Android: May be throttled by Play Store
|
|
598
|
+
- Both: Won't show in development builds
|
|
599
|
+
|
|
600
|
+
## Support
|
|
601
|
+
|
|
602
|
+
- 📖 [Documentation](https://github.com/aoneahsan/capacitor-native-update)
|
|
603
|
+
- 🐛 [Issue Tracker](https://github.com/aoneahsan/capacitor-native-update/issues)
|
|
604
|
+
- 💬 [Discussions](https://github.com/aoneahsan/capacitor-native-update/discussions)
|
|
605
|
+
|
|
606
|
+
Happy updating! 🚀
|
package/docs/README.md
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# Capacitor Native Update - Documentation
|
|
2
|
+
|
|
3
|
+
> ⚠️ **IMPORTANT: Backend Infrastructure Required** ⚠️
|
|
4
|
+
>
|
|
5
|
+
> This plugin requires you to build your own backend infrastructure including:
|
|
6
|
+
> - Update server with API endpoints
|
|
7
|
+
> - Bundle storage and CDN
|
|
8
|
+
> - Signing and security services
|
|
9
|
+
>
|
|
10
|
+
> See [ROADMAP.md](../ROADMAP.md) for complete requirements.
|
|
11
|
+
|
|
12
|
+
Welcome to the comprehensive documentation for **Capacitor Native Update**, a foundation plugin that provides architecture for a complete update lifecycle management solution for Capacitor applications.
|
|
13
|
+
|
|
14
|
+
Created by **Ahsan Mahmood** and open-sourced for the developer community, this plugin combines three essential update features:
|
|
15
|
+
|
|
16
|
+
- **Live/OTA Updates** - Deploy web assets instantly without app store approval
|
|
17
|
+
- **Native App Updates** - Manage app store updates with native UI
|
|
18
|
+
- **App Review Integration** - Request user reviews at optimal moments
|
|
19
|
+
|
|
20
|
+
## 📚 Documentation Overview
|
|
21
|
+
|
|
22
|
+
### Getting Started
|
|
23
|
+
|
|
24
|
+
- [**Installation**](./getting-started/installation.md) - How to install and set up the plugin
|
|
25
|
+
- [**Quick Start**](./getting-started/quick-start.md) - Get up and running in minutes
|
|
26
|
+
- [**Configuration**](./getting-started/configuration.md) - Detailed configuration options
|
|
27
|
+
|
|
28
|
+
### Features
|
|
29
|
+
|
|
30
|
+
- [**Live Updates**](./features/live-updates.md) - Deploy JavaScript/HTML/CSS updates instantly
|
|
31
|
+
- [**App Updates**](./features/app-updates.md) - Native app store update management
|
|
32
|
+
- [**App Reviews**](./features/app-reviews.md) - In-app review requests
|
|
33
|
+
|
|
34
|
+
### Guides
|
|
35
|
+
|
|
36
|
+
- [**Security Best Practices**](./guides/security-best-practices.md) - Implement secure updates
|
|
37
|
+
- [**Migration Guide**](./guides/migration-guide.md) - Migrate from other update solutions
|
|
38
|
+
- [**Troubleshooting**](./guides/troubleshooting.md) - Common issues and solutions
|
|
39
|
+
|
|
40
|
+
### API Reference
|
|
41
|
+
|
|
42
|
+
- [**Live Update API**](./api/live-update-api.md) - Complete API for OTA updates
|
|
43
|
+
- [**App Update API**](./api/app-update-api.md) - Native app update methods
|
|
44
|
+
- [**App Review API**](./api/app-review-api.md) - Review request methods
|
|
45
|
+
- [**Events API**](./api/events-api.md) - Event listeners and handlers
|
|
46
|
+
|
|
47
|
+
### Examples
|
|
48
|
+
|
|
49
|
+
- [**Basic Usage**](./examples/basic-usage.md) - Simple implementation examples
|
|
50
|
+
- [**Advanced Scenarios**](./examples/advanced-scenarios.md) - Complex use cases
|
|
51
|
+
- [**Integration Examples**](./examples/integration-examples.md) - Framework-specific integrations
|
|
52
|
+
|
|
53
|
+
### Production
|
|
54
|
+
|
|
55
|
+
- [**Production Readiness**](./production-readiness.md) - Checklist and best practices for production deployment
|
|
56
|
+
|
|
57
|
+
## 🚀 Quick Links
|
|
58
|
+
|
|
59
|
+
- **NPM Package**: [capacitor-native-update](https://www.npmjs.com/package/capacitor-native-update)
|
|
60
|
+
- **GitHub Repository**: [aoneahsan/capacitor-native-update](https://github.com/aoneahsan/capacitor-native-update)
|
|
61
|
+
- **Issue Tracker**: [GitHub Issues](https://github.com/aoneahsan/capacitor-native-update/issues)
|
|
62
|
+
- **Author**: [Ahsan Mahmood](https://aoneahsan.com)
|
|
63
|
+
|
|
64
|
+
## 💡 Key Features
|
|
65
|
+
|
|
66
|
+
### Type-Safe
|
|
67
|
+
|
|
68
|
+
Full TypeScript support with comprehensive type definitions for all methods and interfaces.
|
|
69
|
+
|
|
70
|
+
### Framework Independent
|
|
71
|
+
|
|
72
|
+
Works with any JavaScript framework - React, Vue, Angular, or vanilla JavaScript.
|
|
73
|
+
|
|
74
|
+
### Secure by Design
|
|
75
|
+
|
|
76
|
+
Built-in security features including checksum validation, signature verification, and HTTPS enforcement.
|
|
77
|
+
|
|
78
|
+
### Performance Optimized
|
|
79
|
+
|
|
80
|
+
Efficient bundle management with delta updates and background downloading capabilities.
|
|
81
|
+
|
|
82
|
+
### Cross-Platform
|
|
83
|
+
|
|
84
|
+
Consistent API across iOS, Android, and Web platforms with platform-specific optimizations.
|
|
85
|
+
|
|
86
|
+
## 📋 Prerequisites
|
|
87
|
+
|
|
88
|
+
- Capacitor 7.0.0 or higher
|
|
89
|
+
- iOS 13.0+ for iOS apps
|
|
90
|
+
- Android 5.0+ (API level 21) for Android apps
|
|
91
|
+
- Node.js 18+ for development
|
|
92
|
+
|
|
93
|
+
## 🤝 Contributing
|
|
94
|
+
|
|
95
|
+
We welcome contributions from the community! Please see our [Contributing Guide](https://github.com/aoneahsan/capacitor-native-update/blob/main/CONTRIBUTING.md) for details.
|
|
96
|
+
|
|
97
|
+
## 📄 License
|
|
98
|
+
|
|
99
|
+
This project is licensed under the MIT License. See the [LICENSE](https://github.com/aoneahsan/capacitor-native-update/blob/main/LICENSE) file for details.
|
|
100
|
+
|
|
101
|
+
## 👨💻 About the Author
|
|
102
|
+
|
|
103
|
+
**Ahsan Mahmood** is a passionate developer dedicated to creating high-quality, open-source tools for the developer community.
|
|
104
|
+
|
|
105
|
+
- 🌐 Portfolio: [aoneahsan.com](https://aoneahsan.com)
|
|
106
|
+
- 💼 LinkedIn: [aoneahsan](https://linkedin.com/in/aoneahsan)
|
|
107
|
+
- 📧 Email: aoneahsan@gmail.com
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
Made with ❤️ by Ahsan Mahmood for the developer community
|