native-update 1.1.4 → 1.2.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/NativeUpdate.podspec +1 -0
- package/android/src/main/java/com/aoneahsan/nativeupdate/AppUpdatePlugin.kt +41 -0
- package/android/src/main/java/com/aoneahsan/nativeupdate/LiveUpdatePlugin.kt +12 -0
- package/android/src/main/java/com/aoneahsan/nativeupdate/NativeUpdatePlugin.kt +52 -1
- package/backend-template/README.md +56 -0
- package/backend-template/package.json +20 -0
- package/backend-template/server.js +121 -0
- package/dist/esm/__tests__/bundle-manager.test.js +1 -0
- package/dist/esm/__tests__/bundle-manager.test.js.map +1 -1
- package/dist/esm/__tests__/config.test.js +1 -0
- package/dist/esm/__tests__/config.test.js.map +1 -1
- package/dist/esm/__tests__/integration.test.js.map +1 -1
- package/dist/esm/__tests__/security.test.js.map +1 -1
- package/dist/esm/app-review/app-review-manager.d.ts +2 -2
- package/dist/esm/app-review/app-review-manager.js.map +1 -1
- package/dist/esm/app-review/platform-review-handler.js.map +1 -1
- package/dist/esm/app-review/review-conditions-checker.d.ts +1 -1
- package/dist/esm/app-review/review-conditions-checker.js.map +1 -1
- package/dist/esm/app-review/types.d.ts +1 -1
- package/dist/esm/app-update/app-update-manager.d.ts +1 -1
- package/dist/esm/app-update/app-update-manager.js.map +1 -1
- package/dist/esm/app-update/app-update-notifier.js.map +1 -1
- package/dist/esm/app-update/platform-app-update.js.map +1 -1
- package/dist/esm/background-update/background-scheduler.js.map +1 -1
- package/dist/esm/core/analytics.d.ts +7 -7
- package/dist/esm/core/analytics.js.map +1 -1
- package/dist/esm/core/event-emitter.d.ts +2 -2
- package/dist/esm/core/event-emitter.js.map +1 -1
- package/dist/esm/core/performance.js +16 -2
- package/dist/esm/core/performance.js.map +1 -1
- package/dist/esm/core/security.d.ts +13 -2
- package/dist/esm/core/security.js +13 -3
- package/dist/esm/core/security.js.map +1 -1
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/live-update/bundle-manager.js +16 -1
- package/dist/esm/live-update/bundle-manager.js.map +1 -1
- package/dist/esm/live-update/download-manager.d.ts +8 -0
- package/dist/esm/live-update/download-manager.js +54 -7
- package/dist/esm/live-update/download-manager.js.map +1 -1
- package/dist/esm/plugin.js +3 -1
- package/dist/esm/plugin.js.map +1 -1
- package/dist/plugin.cjs.js +1 -1
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.esm.js +1 -1
- package/dist/plugin.esm.js.map +1 -1
- package/dist/plugin.js +2 -2
- package/dist/plugin.js.map +1 -1
- package/docs/COMPREHENSIVE_AUDIT_REPORT.md +526 -0
- package/docs/FIREBASE_INTEGRATION_TRACKER.md +321 -0
- package/docs/KNOWN_LIMITATIONS.md +203 -0
- package/docs/PROJECT_COMPLETION_TRACKER.md +243 -0
- package/docs/api/background-update-api.md +157 -0
- package/docs/api/live-update-api.md +16 -0
- package/ios/Plugin/AppUpdate/AppUpdatePlugin.swift +15 -0
- package/ios/Plugin/LiveUpdate/LiveUpdatePlugin.swift +74 -26
- package/ios/Plugin/NativeUpdatePlugin.swift +45 -0
- package/package.json +28 -27
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
# Project Completion Tracker
|
|
2
|
+
|
|
3
|
+
**Last Updated**: 2025-12-26
|
|
4
|
+
**Project**: Native Update - Capacitor Plugin
|
|
5
|
+
**Version**: 1.1.6
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## ✅ COMPLETED FEATURES
|
|
10
|
+
|
|
11
|
+
### Core TypeScript Implementation
|
|
12
|
+
- [x] Plugin architecture with proper interfaces (`src/definitions.ts`)
|
|
13
|
+
- [x] Live update manager (`src/live-update/update-manager.ts`)
|
|
14
|
+
- [x] Bundle manager with download and installation (`src/live-update/bundle-manager.ts`)
|
|
15
|
+
- [x] Version manager with semantic versioning (`src/live-update/version-manager.ts`)
|
|
16
|
+
- [x] Download manager with progress tracking (`src/live-update/download-manager.ts`)
|
|
17
|
+
- [x] Certificate pinning for secure connections (`src/live-update/certificate-pinning.ts`)
|
|
18
|
+
- [x] App update checker (`src/app-update/app-update-checker.ts`)
|
|
19
|
+
- [x] App update installer (`src/app-update/app-update-installer.ts`)
|
|
20
|
+
- [x] App update manager (`src/app-update/app-update-manager.ts`)
|
|
21
|
+
- [x] App update notifier with UI (`src/app-update/app-update-notifier.ts`)
|
|
22
|
+
- [x] Platform app update integration (`src/app-update/platform-app-update.ts`)
|
|
23
|
+
- [x] App review manager (`src/app-review/app-review-manager.ts`)
|
|
24
|
+
- [x] Platform review handler (`src/app-review/platform-review-handler.ts`)
|
|
25
|
+
- [x] Review conditions checker (`src/app-review/review-conditions-checker.ts`)
|
|
26
|
+
- [x] Review rate limiter (`src/app-review/review-rate-limiter.ts`)
|
|
27
|
+
- [x] Background scheduler (`src/background-update/background-scheduler.ts`)
|
|
28
|
+
- [x] Notification manager (`src/background-update/notification-manager.ts`)
|
|
29
|
+
|
|
30
|
+
### Core Infrastructure
|
|
31
|
+
- [x] Analytics framework (`src/core/analytics.ts`)
|
|
32
|
+
- [x] Cache manager (`src/core/cache-manager.ts`)
|
|
33
|
+
- [x] Configuration system (`src/core/config.ts`)
|
|
34
|
+
- [x] Error handling (`src/core/errors.ts`)
|
|
35
|
+
- [x] Event emitter (`src/core/event-emitter.ts`)
|
|
36
|
+
- [x] Logger (`src/core/logger.ts`)
|
|
37
|
+
- [x] Performance monitoring (`src/core/performance.ts`)
|
|
38
|
+
- [x] Plugin manager (`src/core/plugin-manager.ts`)
|
|
39
|
+
- [x] Security utilities (`src/core/security.ts`)
|
|
40
|
+
|
|
41
|
+
### Security Implementation
|
|
42
|
+
- [x] Crypto utilities (`src/security/crypto.ts`)
|
|
43
|
+
- [x] Input/output validator (`src/security/validator.ts`)
|
|
44
|
+
- [x] SHA-256 checksum verification
|
|
45
|
+
- [x] RSA/ECDSA signature verification
|
|
46
|
+
- [x] HTTPS enforcement
|
|
47
|
+
- [x] Certificate pinning architecture
|
|
48
|
+
|
|
49
|
+
### Native Implementations
|
|
50
|
+
|
|
51
|
+
#### iOS (Swift)
|
|
52
|
+
- [x] Main plugin class (`ios/Plugin/NativeUpdatePlugin.swift`)
|
|
53
|
+
- [x] Live update implementation (`ios/Plugin/LiveUpdate/LiveUpdatePlugin.swift`)
|
|
54
|
+
- [x] Bundle manager (`ios/Plugin/LiveUpdate/BundleManager.swift`)
|
|
55
|
+
- [x] Security manager (`ios/Plugin/Security/SecurityManager.swift`)
|
|
56
|
+
- [x] App update plugin (`ios/Plugin/AppUpdate/AppUpdatePlugin.swift`)
|
|
57
|
+
- [x] App review plugin (`ios/Plugin/AppReview/AppReviewPlugin.swift`)
|
|
58
|
+
- [x] Background update plugin (`ios/Plugin/BackgroundUpdate/BackgroundUpdatePlugin.swift`)
|
|
59
|
+
|
|
60
|
+
#### Android (Kotlin)
|
|
61
|
+
- [x] Main plugin class (`android/src/main/java/com/aoneahsan/nativeupdate/NativeUpdatePlugin.kt`)
|
|
62
|
+
- [x] Live update implementation (`android/src/main/java/com/aoneahsan/nativeupdate/LiveUpdatePlugin.kt`)
|
|
63
|
+
- [x] Bundle manager (`android/src/main/java/com/aoneahsan/nativeupdate/BundleManager.kt`)
|
|
64
|
+
- [x] Security manager (`android/src/main/java/com/aoneahsan/nativeupdate/SecurityManager.kt`)
|
|
65
|
+
- [x] App update plugin (`android/src/main/java/com/aoneahsan/nativeupdate/AppUpdatePlugin.kt`)
|
|
66
|
+
- [x] App review plugin (`android/src/main/java/com/aoneahsan/nativeupdate/AppReviewPlugin.kt`)
|
|
67
|
+
- [x] Background update plugin (`android/src/main/java/com/aoneahsan/nativeupdate/BackgroundUpdatePlugin.kt`)
|
|
68
|
+
|
|
69
|
+
### Testing Infrastructure
|
|
70
|
+
- [x] Vitest configuration (`vitest.config.ts`)
|
|
71
|
+
- [x] Bundle manager tests (`src/__tests__/bundle-manager.test.ts`)
|
|
72
|
+
- [x] Config tests (`src/__tests__/config.test.ts`)
|
|
73
|
+
- [x] Integration tests (`src/__tests__/integration.test.ts`)
|
|
74
|
+
- [x] Security tests (`src/__tests__/security.test.ts`)
|
|
75
|
+
- [x] Version manager tests (`src/__tests__/version-manager.test.ts`)
|
|
76
|
+
|
|
77
|
+
### CLI Tools
|
|
78
|
+
- [x] Main CLI (`cli/index.js`)
|
|
79
|
+
- [x] Init command (`cli/commands/init.js`)
|
|
80
|
+
- [x] Bundle create command (`cli/commands/bundle-create.js`)
|
|
81
|
+
- [x] Bundle sign command (`cli/commands/bundle-sign.js`)
|
|
82
|
+
- [x] Bundle verify command (`cli/commands/bundle-verify.js`)
|
|
83
|
+
- [x] Keys generate command (`cli/commands/keys-generate.js`)
|
|
84
|
+
- [x] Backend create command (`cli/commands/backend-create.js`)
|
|
85
|
+
- [x] Server start command (`cli/commands/server-start.js`)
|
|
86
|
+
- [x] Monitor command (`cli/commands/monitor.js`)
|
|
87
|
+
|
|
88
|
+
### Backend Infrastructure
|
|
89
|
+
|
|
90
|
+
#### Production Backend (Node.js + SQLite)
|
|
91
|
+
- [x] Main server (`production-backend/src/index.js`)
|
|
92
|
+
- [x] Database initialization (`production-backend/src/database/init.js`)
|
|
93
|
+
- [x] Auth middleware (`production-backend/src/middleware/auth.js`)
|
|
94
|
+
- [x] Error middleware (`production-backend/src/middleware/error.js`)
|
|
95
|
+
- [x] Logging middleware (`production-backend/src/middleware/logging.js`)
|
|
96
|
+
- [x] Validation middleware (`production-backend/src/middleware/validation.js`)
|
|
97
|
+
- [x] Analytics routes (`production-backend/src/routes/analytics.js`)
|
|
98
|
+
- [x] Auth routes (`production-backend/src/routes/auth.js`)
|
|
99
|
+
- [x] Bundles routes (`production-backend/src/routes/bundles.js`)
|
|
100
|
+
- [x] Health routes (`production-backend/src/routes/health.js`)
|
|
101
|
+
- [x] Updates routes (`production-backend/src/routes/updates.js`)
|
|
102
|
+
- [x] Logger utility (`production-backend/src/utils/logger.js`)
|
|
103
|
+
|
|
104
|
+
#### Firebase Backend Example
|
|
105
|
+
- [x] Firebase Functions (`example-app/firebase-backend/src/index.ts`)
|
|
106
|
+
- [x] Auth middleware (`example-app/firebase-backend/src/middleware/auth.ts`)
|
|
107
|
+
- [x] Analytics routes (`example-app/firebase-backend/src/routes/analytics.ts`)
|
|
108
|
+
- [x] Bundles routes (`example-app/firebase-backend/src/routes/bundles.ts`)
|
|
109
|
+
- [x] Updates routes (`example-app/firebase-backend/src/routes/updates.ts`)
|
|
110
|
+
- [x] Validation utils (`example-app/firebase-backend/src/utils/validation.ts`)
|
|
111
|
+
- [x] Version utils (`example-app/firebase-backend/src/utils/version.ts`)
|
|
112
|
+
- [x] Firestore indexes (`example-app/firebase-backend/firestore.indexes.json`)
|
|
113
|
+
- [x] Firestore rules (`example-app/firebase-backend/firestore.rules`)
|
|
114
|
+
- [x] Storage rules (`example-app/firebase-backend/storage.rules`)
|
|
115
|
+
|
|
116
|
+
#### Backend Template (Express)
|
|
117
|
+
- [x] Simple server (`backend-template/server.js`)
|
|
118
|
+
|
|
119
|
+
### Documentation
|
|
120
|
+
- [x] Main README (`Readme.md`)
|
|
121
|
+
- [x] API documentation (`API.md`)
|
|
122
|
+
- [x] Changelog (`CHANGELOG.md`)
|
|
123
|
+
- [x] Contributing guide (`CONTRIBUTING.md`)
|
|
124
|
+
- [x] Security policy (`SECURITY.md`)
|
|
125
|
+
- [x] Features overview (`FEATURES.md`)
|
|
126
|
+
- [x] Quick start guide (`docs/QUICK_START.md`)
|
|
127
|
+
- [x] Live updates guide (`docs/LIVE_UPDATES_GUIDE.md`)
|
|
128
|
+
- [x] Native updates guide (`docs/NATIVE_UPDATES_GUIDE.md`)
|
|
129
|
+
- [x] App review guide (`docs/APP_REVIEW_GUIDE.md`)
|
|
130
|
+
- [x] Bundle signing guide (`docs/BUNDLE_SIGNING.md`)
|
|
131
|
+
- [x] Background updates (`docs/background-updates.md`)
|
|
132
|
+
- [x] CLI reference (`docs/cli-reference.md`)
|
|
133
|
+
- [x] Migration guide (`docs/MIGRATION.md`)
|
|
134
|
+
- [x] Production readiness (`docs/production-readiness.md`)
|
|
135
|
+
- [x] Server requirements (`docs/server-requirements.md`)
|
|
136
|
+
- [x] Installation (`docs/getting-started/installation.md`)
|
|
137
|
+
- [x] Configuration (`docs/getting-started/configuration.md`)
|
|
138
|
+
- [x] Quick start (`docs/getting-started/quick-start.md`)
|
|
139
|
+
- [x] Live updates feature (`docs/features/live-updates.md`)
|
|
140
|
+
- [x] App updates feature (`docs/features/app-updates.md`)
|
|
141
|
+
- [x] App reviews feature (`docs/features/app-reviews.md`)
|
|
142
|
+
- [x] Basic usage examples (`docs/examples/basic-usage.md`)
|
|
143
|
+
- [x] Advanced scenarios (`docs/examples/advanced-scenarios.md`)
|
|
144
|
+
- [x] Deployment guide (`docs/guides/deployment-guide.md`)
|
|
145
|
+
- [x] Key management (`docs/guides/key-management.md`)
|
|
146
|
+
- [x] Migration from CodePush (`docs/guides/migration-from-codepush.md`)
|
|
147
|
+
- [x] Security best practices (`docs/guides/security-best-practices.md`)
|
|
148
|
+
- [x] Testing guide (`docs/guides/testing-guide.md`)
|
|
149
|
+
- [x] Certificate pinning (`docs/security/certificate-pinning.md`)
|
|
150
|
+
- [x] API references for all modules (`docs/api/`)
|
|
151
|
+
|
|
152
|
+
### Example Applications
|
|
153
|
+
- [x] Basic example app (`example/`)
|
|
154
|
+
- [x] Advanced example app with Firebase (`example-app/`)
|
|
155
|
+
- [x] Test app for development (`test-app/`)
|
|
156
|
+
|
|
157
|
+
### Build & Development Tools
|
|
158
|
+
- [x] TypeScript configuration (`tsconfig.json`, `tsconfig.node.json`)
|
|
159
|
+
- [x] Rollup bundler config (`rollup.config.js`)
|
|
160
|
+
- [x] ESLint config (`eslint.config.js`)
|
|
161
|
+
- [x] Prettier config (`.prettierrc`)
|
|
162
|
+
- [x] Vitest config (`vitest.config.ts`)
|
|
163
|
+
- [x] Package.json with all scripts
|
|
164
|
+
- [x] NVM version file (`.nvmrc`)
|
|
165
|
+
- [x] EditorConfig (`.editorconfig`)
|
|
166
|
+
- [x] Capacitor config (`capacitor.config.ts`)
|
|
167
|
+
- [x] CocoaPods spec (`NativeUpdate.podspec`)
|
|
168
|
+
|
|
169
|
+
### Utilities
|
|
170
|
+
- [x] Bundle creator tool (`tools/bundle-creator.js`)
|
|
171
|
+
- [x] Bundle signer tool (`tools/bundle-signer.js`)
|
|
172
|
+
- [x] Server example (`server-example/`)
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
## ⚠️ PENDING FIXES (MUST COMPLETE NOW)
|
|
177
|
+
|
|
178
|
+
### Code Quality Issues
|
|
179
|
+
- [ ] **CRITICAL**: Fix all 40 ESLint warnings (TypeScript `any` types) - MUST FIX NOW
|
|
180
|
+
- [ ] **CRITICAL**: Remove placeholder code in `src/core/performance.ts` (storage check) - MUST IMPLEMENT NOW
|
|
181
|
+
- [ ] **CRITICAL**: Remove placeholder code in `src/core/security.ts` (certificate pinning note) - MUST CLARIFY NOW
|
|
182
|
+
- [ ] **CRITICAL**: Remove placeholder code in `ios/Plugin/LiveUpdate/LiveUpdatePlugin.swift` (file copy & unzip) - MUST IMPLEMENT NOW
|
|
183
|
+
|
|
184
|
+
### Documentation Updates
|
|
185
|
+
- [ ] Update `FINAL_STATUS.md` to reflect current TRUE status
|
|
186
|
+
- [ ] Update `PRODUCTION_STATUS.md` to reflect current TRUE status
|
|
187
|
+
- [ ] Update `REMAINING_FEATURES.md` to reflect ACTUAL remaining work
|
|
188
|
+
- [ ] Update `ROADMAP.md` to reflect completed items
|
|
189
|
+
- [ ] Create Firebase indexes/rules verification document
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
## 🚫 NOT APPLICABLE / NOT NEEDED
|
|
194
|
+
|
|
195
|
+
### Items That Don't Apply
|
|
196
|
+
- ❌ Vite logging level change (not a Vite project, uses Rollup)
|
|
197
|
+
- ❌ Firebase permissions errors in core plugin (Firebase only used in example-app)
|
|
198
|
+
|
|
199
|
+
---
|
|
200
|
+
|
|
201
|
+
## 📊 COMPLETION STATISTICS
|
|
202
|
+
|
|
203
|
+
### Overall Progress
|
|
204
|
+
- **Core Plugin**: 100% Complete
|
|
205
|
+
- **Native Implementations**: 95% Complete (some placeholders need implementation)
|
|
206
|
+
- **CLI Tools**: 100% Complete
|
|
207
|
+
- **Backend Examples**: 100% Complete
|
|
208
|
+
- **Documentation**: 100% Complete
|
|
209
|
+
- **Testing**: 100% Complete
|
|
210
|
+
- **Code Quality**: 90% (40 ESLint warnings to fix)
|
|
211
|
+
|
|
212
|
+
### Issues to Resolve
|
|
213
|
+
1. **40 ESLint warnings** - Replace `any` with proper types
|
|
214
|
+
2. **3 code placeholders** - Implement or document as intentional
|
|
215
|
+
3. **Documentation inconsistency** - Status files show conflicting states
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
|
|
219
|
+
## 🎯 IMMEDIATE ACTION ITEMS
|
|
220
|
+
|
|
221
|
+
1. ✅ Fix all 40 ESLint `any` type warnings
|
|
222
|
+
2. ✅ Remove or implement all placeholder code
|
|
223
|
+
3. ✅ Create Firebase tracking document
|
|
224
|
+
4. ✅ Update all status documents for consistency
|
|
225
|
+
5. ✅ Run final build with zero warnings
|
|
226
|
+
6. ✅ Verify no errors or warnings in entire project
|
|
227
|
+
|
|
228
|
+
---
|
|
229
|
+
|
|
230
|
+
## 📝 NOTES
|
|
231
|
+
|
|
232
|
+
- This is a **Capacitor plugin package**, not a web app, so:
|
|
233
|
+
- No Vite (uses Rollup instead)
|
|
234
|
+
- No browser-based development server
|
|
235
|
+
- Firebase only used in example-app, not core plugin
|
|
236
|
+
|
|
237
|
+
- The plugin provides:
|
|
238
|
+
- Live/OTA updates for web assets
|
|
239
|
+
- Native app store update checking
|
|
240
|
+
- In-app review prompts
|
|
241
|
+
|
|
242
|
+
- Backend implementation is left to users (examples provided)
|
|
243
|
+
- Real device testing recommended before production use
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
# Background Update API Reference
|
|
2
|
+
|
|
3
|
+
Complete API documentation for background update functionality.
|
|
4
|
+
|
|
5
|
+
## Methods
|
|
6
|
+
|
|
7
|
+
### enableBackgroundUpdates(config)
|
|
8
|
+
|
|
9
|
+
Enable background update checking.
|
|
10
|
+
|
|
11
|
+
```typescript
|
|
12
|
+
await NativeUpdate.enableBackgroundUpdates({
|
|
13
|
+
checkInterval: 3600000, // Check every hour (in ms)
|
|
14
|
+
requireWifi: true, // Only check on WiFi
|
|
15
|
+
requireCharging: false, // Don't require charging
|
|
16
|
+
updateTypes: ['live', 'native'], // Check both update types
|
|
17
|
+
notificationConfig: {
|
|
18
|
+
enabled: true,
|
|
19
|
+
title: 'Update Available',
|
|
20
|
+
autoCancel: true
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### disableBackgroundUpdates()
|
|
26
|
+
|
|
27
|
+
Disable all background update checks.
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
await NativeUpdate.disableBackgroundUpdates();
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### getBackgroundUpdateStatus()
|
|
34
|
+
|
|
35
|
+
Get current background update configuration and status.
|
|
36
|
+
|
|
37
|
+
```typescript
|
|
38
|
+
const status = await NativeUpdate.getBackgroundUpdateStatus();
|
|
39
|
+
// Returns:
|
|
40
|
+
{
|
|
41
|
+
enabled: boolean;
|
|
42
|
+
lastCheckTime?: number;
|
|
43
|
+
nextScheduledCheck?: number;
|
|
44
|
+
checkInterval?: number;
|
|
45
|
+
updateTypes: string[];
|
|
46
|
+
notificationEnabled: boolean;
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### scheduleBackgroundCheck(options)
|
|
51
|
+
|
|
52
|
+
Schedule a one-time background check.
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
await NativeUpdate.scheduleBackgroundCheck({
|
|
56
|
+
delay: 60000, // Check in 1 minute
|
|
57
|
+
type: 'live' // Check for live updates only
|
|
58
|
+
});
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### triggerBackgroundCheck()
|
|
62
|
+
|
|
63
|
+
Immediately trigger a background update check.
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
const result = await NativeUpdate.triggerBackgroundCheck();
|
|
67
|
+
// Returns:
|
|
68
|
+
{
|
|
69
|
+
liveUpdateAvailable: boolean;
|
|
70
|
+
nativeUpdateAvailable: boolean;
|
|
71
|
+
error?: string;
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### setNotificationPreferences(preferences)
|
|
76
|
+
|
|
77
|
+
Configure notification preferences for background updates.
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
await NativeUpdate.setNotificationPreferences({
|
|
81
|
+
enabled: true,
|
|
82
|
+
showProgress: true,
|
|
83
|
+
soundEnabled: false,
|
|
84
|
+
vibrationEnabled: true,
|
|
85
|
+
ledColor: '#00FF00',
|
|
86
|
+
importance: 'HIGH'
|
|
87
|
+
});
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### getNotificationPermissions()
|
|
91
|
+
|
|
92
|
+
Check current notification permissions.
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
const permissions = await NativeUpdate.getNotificationPermissions();
|
|
96
|
+
// Returns:
|
|
97
|
+
{
|
|
98
|
+
granted: boolean;
|
|
99
|
+
canRequestPermission: boolean;
|
|
100
|
+
permanentlyDenied: boolean;
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### requestNotificationPermissions()
|
|
105
|
+
|
|
106
|
+
Request notification permissions from the user.
|
|
107
|
+
|
|
108
|
+
```typescript
|
|
109
|
+
const result = await NativeUpdate.requestNotificationPermissions();
|
|
110
|
+
// Returns:
|
|
111
|
+
{
|
|
112
|
+
granted: boolean;
|
|
113
|
+
permanentlyDenied: boolean;
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Events
|
|
118
|
+
|
|
119
|
+
### backgroundUpdateProgress
|
|
120
|
+
|
|
121
|
+
Fired during background update operations.
|
|
122
|
+
|
|
123
|
+
```typescript
|
|
124
|
+
NativeUpdate.addListener('backgroundUpdateProgress', (event) => {
|
|
125
|
+
console.log('Background update:', event.status);
|
|
126
|
+
// event.type: 'live' | 'native'
|
|
127
|
+
// event.status: 'checking' | 'downloading' | 'completed' | 'failed'
|
|
128
|
+
});
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### backgroundUpdateNotification
|
|
132
|
+
|
|
133
|
+
Fired when background check finds an update.
|
|
134
|
+
|
|
135
|
+
```typescript
|
|
136
|
+
NativeUpdate.addListener('backgroundUpdateNotification', (event) => {
|
|
137
|
+
console.log('Update available:', event.updateAvailable);
|
|
138
|
+
// event.type: 'live' | 'native'
|
|
139
|
+
// event.version: string
|
|
140
|
+
});
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## Platform Notes
|
|
144
|
+
|
|
145
|
+
### Android
|
|
146
|
+
- Uses WorkManager for reliable scheduling
|
|
147
|
+
- Respects battery optimization settings
|
|
148
|
+
- Requires notification permission for user alerts
|
|
149
|
+
|
|
150
|
+
### iOS
|
|
151
|
+
- Uses BackgroundTasks framework
|
|
152
|
+
- Limited by iOS background execution policies
|
|
153
|
+
- May not run exactly at scheduled times
|
|
154
|
+
|
|
155
|
+
### Web
|
|
156
|
+
- Uses Service Workers when available
|
|
157
|
+
- Falls back to periodic checks when app is active
|
|
@@ -148,6 +148,22 @@ Notify that the app has successfully started with the new bundle.
|
|
|
148
148
|
await NativeUpdate.notifyAppReady();
|
|
149
149
|
```
|
|
150
150
|
|
|
151
|
+
### getLatest()
|
|
152
|
+
|
|
153
|
+
Get information about the latest available update from the server.
|
|
154
|
+
|
|
155
|
+
```typescript
|
|
156
|
+
const latest = await NativeUpdate.getLatest();
|
|
157
|
+
// Returns:
|
|
158
|
+
{
|
|
159
|
+
available: boolean; // Whether an update is available
|
|
160
|
+
version?: string; // Version number of the latest update
|
|
161
|
+
url?: string; // Download URL for the update
|
|
162
|
+
mandatory?: boolean; // Whether this is a mandatory update
|
|
163
|
+
notes?: string; // Release notes for the update
|
|
164
|
+
size?: number; // Size in bytes of the update bundle
|
|
165
|
+
}
|
|
166
|
+
```
|
|
151
167
|
|
|
152
168
|
### setChannel(channel)
|
|
153
169
|
|
|
@@ -6,11 +6,16 @@ class AppUpdatePlugin {
|
|
|
6
6
|
private weak var plugin: CAPPlugin?
|
|
7
7
|
private var config: [String: Any]?
|
|
8
8
|
private let iTunesLookupURL = "https://itunes.apple.com/lookup"
|
|
9
|
+
private var eventListener: ((String, [String: Any]) -> Void)?
|
|
9
10
|
|
|
10
11
|
init(plugin: CAPPlugin) {
|
|
11
12
|
self.plugin = plugin
|
|
12
13
|
}
|
|
13
14
|
|
|
15
|
+
func setEventListener(_ listener: @escaping (String, [String: Any]) -> Void) {
|
|
16
|
+
self.eventListener = listener
|
|
17
|
+
}
|
|
18
|
+
|
|
14
19
|
func configure(_ config: [String: Any]) throws {
|
|
15
20
|
self.config = config
|
|
16
21
|
}
|
|
@@ -43,6 +48,16 @@ class AppUpdatePlugin {
|
|
|
43
48
|
result["clientVersionStalenessDays"] = days
|
|
44
49
|
}
|
|
45
50
|
}
|
|
51
|
+
|
|
52
|
+
// Emit available event
|
|
53
|
+
var availableData: [String: Any] = [
|
|
54
|
+
"currentVersion": currentVersion,
|
|
55
|
+
"availableVersion": storeVersion
|
|
56
|
+
]
|
|
57
|
+
if let priority = result["updatePriority"] as? Int {
|
|
58
|
+
availableData["updatePriority"] = priority
|
|
59
|
+
}
|
|
60
|
+
eventListener?("appUpdateAvailable", availableData)
|
|
46
61
|
}
|
|
47
62
|
|
|
48
63
|
// iOS doesn't have the same update types as Android
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import Foundation
|
|
2
2
|
import Capacitor
|
|
3
3
|
import CommonCrypto
|
|
4
|
+
import ZIPFoundation
|
|
4
5
|
|
|
5
6
|
class LiveUpdatePlugin {
|
|
6
7
|
private weak var plugin: CAPPlugin?
|
|
@@ -517,6 +518,12 @@ class LiveUpdatePlugin {
|
|
|
517
518
|
defaults.set(bundles, forKey: "native_update_bundles")
|
|
518
519
|
}
|
|
519
520
|
|
|
521
|
+
func cleanup() {
|
|
522
|
+
// Clean up any resources
|
|
523
|
+
downloadTask?.cancel()
|
|
524
|
+
downloadTask = nil
|
|
525
|
+
}
|
|
526
|
+
|
|
520
527
|
private func cleanupOldBundles(keepVersions: Int) {
|
|
521
528
|
let bundles = getAllBundles().sorted { bundle1, bundle2 in
|
|
522
529
|
let time1 = bundle1["downloadTime"] as? Double ?? 0
|
|
@@ -542,40 +549,81 @@ class LiveUpdatePlugin {
|
|
|
542
549
|
|
|
543
550
|
private func extractAndApplyBundle(_ bundleUrl: URL, bundleId: String) throws {
|
|
544
551
|
let extractedPath = getUpdatesDirectory().appendingPathComponent(bundleId).appendingPathComponent("www")
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
552
|
+
|
|
553
|
+
do {
|
|
554
|
+
// Extract the zip bundle
|
|
555
|
+
try extractZipBundle(from: bundleUrl, to: extractedPath)
|
|
556
|
+
|
|
557
|
+
// Update bundle info with extracted path
|
|
558
|
+
var bundleInfo = getAllBundles().first { $0["bundleId"] as? String == bundleId } ?? [:]
|
|
559
|
+
bundleInfo["extractedPath"] = extractedPath.path
|
|
560
|
+
bundleInfo["status"] = "READY"
|
|
561
|
+
saveBundleInfo(bundleInfo)
|
|
562
|
+
|
|
563
|
+
// Configure WebView to use new path
|
|
564
|
+
configureWebViewPath(extractedPath.path)
|
|
565
|
+
} catch {
|
|
566
|
+
// Get the safe bundle path (current working bundle)
|
|
567
|
+
let safePath = UserDefaults.standard.string(forKey: "native_update_webview_path") ?? "/"
|
|
568
|
+
|
|
569
|
+
// Rollback to safe bundle
|
|
570
|
+
try? rollbackToSafeBundle(currentPath: extractedPath.path, safePath: safePath)
|
|
571
|
+
|
|
572
|
+
// Re-throw the error
|
|
573
|
+
throw error
|
|
574
|
+
}
|
|
557
575
|
}
|
|
558
576
|
|
|
559
577
|
private func extractZipBundle(from zipUrl: URL, to destinationUrl: URL) throws {
|
|
560
|
-
//
|
|
561
|
-
try FileManager.default.createDirectory(at: destinationUrl, withIntermediateDirectories: true)
|
|
562
|
-
|
|
563
|
-
//
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
578
|
+
// Ensure destination directory exists
|
|
579
|
+
try FileManager.default.createDirectory(at: destinationUrl, withIntermediateDirectories: true, attributes: nil)
|
|
580
|
+
|
|
581
|
+
// Extract the ZIP archive using ZIPFoundation
|
|
582
|
+
try FileManager.default.unzipItem(at: zipUrl, to: destinationUrl)
|
|
583
|
+
|
|
584
|
+
// Verify extraction succeeded by checking for index.html
|
|
585
|
+
let indexPath = destinationUrl.appendingPathComponent("index.html")
|
|
586
|
+
guard FileManager.default.fileExists(atPath: indexPath.path) else {
|
|
587
|
+
throw NSError(domain: "LiveUpdatePlugin", code: 6, userInfo: [
|
|
588
|
+
NSLocalizedDescriptionKey: "Bundle extraction failed: index.html not found in extracted bundle"
|
|
589
|
+
])
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
// Clean up the ZIP file after successful extraction
|
|
593
|
+
try? FileManager.default.removeItem(at: zipUrl)
|
|
571
594
|
}
|
|
572
595
|
|
|
573
596
|
private func configureWebViewPath(_ path: String) {
|
|
574
597
|
// Store the active bundle path
|
|
575
598
|
UserDefaults.standard.set(path, forKey: "native_update_webview_path")
|
|
576
|
-
|
|
577
|
-
//
|
|
578
|
-
|
|
599
|
+
|
|
600
|
+
// Configure Capacitor WebView to use the new bundle path
|
|
601
|
+
DispatchQueue.main.async { [weak self] in
|
|
602
|
+
guard let bridge = self?.plugin?.bridge else { return }
|
|
603
|
+
|
|
604
|
+
// Set the server base path to the extracted bundle directory
|
|
605
|
+
bridge.setServerBasePath(path)
|
|
606
|
+
|
|
607
|
+
// Optionally trigger a WebView reload (commented out by default)
|
|
608
|
+
// Uncomment if you want automatic reload after bundle extraction
|
|
609
|
+
// bridge.webView?.reload()
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
private func rollbackToSafeBundle(currentPath: String, safePath: String) throws {
|
|
614
|
+
// Remove the failed bundle directory
|
|
615
|
+
let currentUrl = URL(fileURLWithPath: currentPath)
|
|
616
|
+
try? FileManager.default.removeItem(at: currentUrl)
|
|
617
|
+
|
|
618
|
+
// Restore to the safe bundle
|
|
619
|
+
DispatchQueue.main.async { [weak self] in
|
|
620
|
+
guard let bridge = self?.plugin?.bridge else { return }
|
|
621
|
+
bridge.setServerBasePath(safePath)
|
|
622
|
+
bridge.webView?.reload()
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
// Update stored path
|
|
626
|
+
UserDefaults.standard.set(safePath, forKey: "native_update_webview_path")
|
|
579
627
|
}
|
|
580
628
|
}
|
|
581
629
|
|
|
@@ -8,6 +8,7 @@ public class NativeUpdatePlugin: CAPPlugin {
|
|
|
8
8
|
private var appReviewPlugin: AppReviewPlugin!
|
|
9
9
|
private var backgroundUpdatePlugin: BackgroundUpdatePlugin!
|
|
10
10
|
private var securityManager: SecurityManager!
|
|
11
|
+
private var isInitialized = false
|
|
11
12
|
|
|
12
13
|
override public func load() {
|
|
13
14
|
super.load()
|
|
@@ -27,6 +28,49 @@ public class NativeUpdatePlugin: CAPPlugin {
|
|
|
27
28
|
liveUpdatePlugin.setStateChangeListener { [weak self] state in
|
|
28
29
|
self?.notifyListeners("updateStateChanged", data: state)
|
|
29
30
|
}
|
|
31
|
+
|
|
32
|
+
// Set up app update event listener
|
|
33
|
+
appUpdatePlugin.setEventListener { [weak self] eventName, data in
|
|
34
|
+
self?.notifyListeners(eventName, data: data)
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
@objc func initialize(_ call: CAPPluginCall) {
|
|
39
|
+
guard let config = call.getObject("config") else {
|
|
40
|
+
call.reject("Configuration object is required")
|
|
41
|
+
return
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
do {
|
|
45
|
+
// Initialize with filesystem and preferences if provided
|
|
46
|
+
// In iOS, we typically don't need these as we use native APIs
|
|
47
|
+
|
|
48
|
+
// Apply configuration
|
|
49
|
+
configure(call)
|
|
50
|
+
|
|
51
|
+
isInitialized = true
|
|
52
|
+
call.resolve()
|
|
53
|
+
} catch {
|
|
54
|
+
call.reject("Initialization failed", error.localizedDescription)
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
@objc func isInitialized(_ call: CAPPluginCall) {
|
|
59
|
+
call.resolve(["initialized": isInitialized])
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
@objc func cleanup(_ call: CAPPluginCall) {
|
|
63
|
+
// Clean up any resources
|
|
64
|
+
liveUpdatePlugin.cleanup()
|
|
65
|
+
// Disable background updates through the plugin method
|
|
66
|
+
let disableCall = CAPPluginCall(
|
|
67
|
+
callbackId: "cleanup_disable",
|
|
68
|
+
options: [:],
|
|
69
|
+
success: { _ in },
|
|
70
|
+
error: { _ in }
|
|
71
|
+
)
|
|
72
|
+
backgroundUpdatePlugin.disableBackgroundUpdates(disableCall)
|
|
73
|
+
call.resolve()
|
|
30
74
|
}
|
|
31
75
|
|
|
32
76
|
@objc func configure(_ call: CAPPluginCall) {
|
|
@@ -88,6 +132,7 @@ public class NativeUpdatePlugin: CAPPlugin {
|
|
|
88
132
|
|
|
89
133
|
@objc func reset(_ call: CAPPluginCall) {
|
|
90
134
|
liveUpdatePlugin.reset(call)
|
|
135
|
+
isInitialized = false
|
|
91
136
|
}
|
|
92
137
|
|
|
93
138
|
@objc func current(_ call: CAPPluginCall) {
|