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.
Files changed (58) hide show
  1. package/NativeUpdate.podspec +1 -0
  2. package/android/src/main/java/com/aoneahsan/nativeupdate/AppUpdatePlugin.kt +41 -0
  3. package/android/src/main/java/com/aoneahsan/nativeupdate/LiveUpdatePlugin.kt +12 -0
  4. package/android/src/main/java/com/aoneahsan/nativeupdate/NativeUpdatePlugin.kt +52 -1
  5. package/backend-template/README.md +56 -0
  6. package/backend-template/package.json +20 -0
  7. package/backend-template/server.js +121 -0
  8. package/dist/esm/__tests__/bundle-manager.test.js +1 -0
  9. package/dist/esm/__tests__/bundle-manager.test.js.map +1 -1
  10. package/dist/esm/__tests__/config.test.js +1 -0
  11. package/dist/esm/__tests__/config.test.js.map +1 -1
  12. package/dist/esm/__tests__/integration.test.js.map +1 -1
  13. package/dist/esm/__tests__/security.test.js.map +1 -1
  14. package/dist/esm/app-review/app-review-manager.d.ts +2 -2
  15. package/dist/esm/app-review/app-review-manager.js.map +1 -1
  16. package/dist/esm/app-review/platform-review-handler.js.map +1 -1
  17. package/dist/esm/app-review/review-conditions-checker.d.ts +1 -1
  18. package/dist/esm/app-review/review-conditions-checker.js.map +1 -1
  19. package/dist/esm/app-review/types.d.ts +1 -1
  20. package/dist/esm/app-update/app-update-manager.d.ts +1 -1
  21. package/dist/esm/app-update/app-update-manager.js.map +1 -1
  22. package/dist/esm/app-update/app-update-notifier.js.map +1 -1
  23. package/dist/esm/app-update/platform-app-update.js.map +1 -1
  24. package/dist/esm/background-update/background-scheduler.js.map +1 -1
  25. package/dist/esm/core/analytics.d.ts +7 -7
  26. package/dist/esm/core/analytics.js.map +1 -1
  27. package/dist/esm/core/event-emitter.d.ts +2 -2
  28. package/dist/esm/core/event-emitter.js.map +1 -1
  29. package/dist/esm/core/performance.js +16 -2
  30. package/dist/esm/core/performance.js.map +1 -1
  31. package/dist/esm/core/security.d.ts +13 -2
  32. package/dist/esm/core/security.js +13 -3
  33. package/dist/esm/core/security.js.map +1 -1
  34. package/dist/esm/index.d.ts +1 -1
  35. package/dist/esm/index.js.map +1 -1
  36. package/dist/esm/live-update/bundle-manager.js +16 -1
  37. package/dist/esm/live-update/bundle-manager.js.map +1 -1
  38. package/dist/esm/live-update/download-manager.d.ts +8 -0
  39. package/dist/esm/live-update/download-manager.js +54 -7
  40. package/dist/esm/live-update/download-manager.js.map +1 -1
  41. package/dist/esm/plugin.js +3 -1
  42. package/dist/esm/plugin.js.map +1 -1
  43. package/dist/plugin.cjs.js +1 -1
  44. package/dist/plugin.cjs.js.map +1 -1
  45. package/dist/plugin.esm.js +1 -1
  46. package/dist/plugin.esm.js.map +1 -1
  47. package/dist/plugin.js +2 -2
  48. package/dist/plugin.js.map +1 -1
  49. package/docs/COMPREHENSIVE_AUDIT_REPORT.md +526 -0
  50. package/docs/FIREBASE_INTEGRATION_TRACKER.md +321 -0
  51. package/docs/KNOWN_LIMITATIONS.md +203 -0
  52. package/docs/PROJECT_COMPLETION_TRACKER.md +243 -0
  53. package/docs/api/background-update-api.md +157 -0
  54. package/docs/api/live-update-api.md +16 -0
  55. package/ios/Plugin/AppUpdate/AppUpdatePlugin.swift +15 -0
  56. package/ios/Plugin/LiveUpdate/LiveUpdatePlugin.swift +74 -26
  57. package/ios/Plugin/NativeUpdatePlugin.swift +45 -0
  58. 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
- // Extract the zip bundle
547
- try extractZipBundle(from: bundleUrl, to: extractedPath)
548
-
549
- // Update bundle info with extracted path
550
- var bundleInfo = getAllBundles().first { $0["bundleId"] as? String == bundleId } ?? [:]
551
- bundleInfo["extractedPath"] = extractedPath.path
552
- bundleInfo["status"] = "READY"
553
- saveBundleInfo(bundleInfo)
554
-
555
- // Configure WebView to use new path
556
- configureWebViewPath(extractedPath.path)
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
- // Create destination directory
561
- try FileManager.default.createDirectory(at: destinationUrl, withIntermediateDirectories: true)
562
-
563
- // Use FileManager to extract (requires iOS unzip library or manual implementation)
564
- // For now, we'll use a simple file copy as placeholder
565
- // In production, you would use a library like ZIPFoundation or SSZipArchive
566
-
567
- // This is a placeholder - in real implementation, use a proper unzip library
568
- throw NSError(domain: "LiveUpdatePlugin", code: 5, userInfo: [
569
- NSLocalizedDescriptionKey: "Unzip functionality not implemented. Please integrate a zip library like ZIPFoundation."
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
- // The actual WebView path configuration happens in the main plugin
578
- // when the WebView is loaded or reloaded
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) {