native-update 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (184) hide show
  1. package/CapacitorNativeUpdate.podspec +18 -0
  2. package/LICENSE +21 -0
  3. package/Readme.md +451 -0
  4. package/android/build.gradle +92 -0
  5. package/android/gradle/wrapper/gradle-wrapper.properties +8 -0
  6. package/android/gradle.properties +17 -0
  7. package/android/proguard-rules.pro +29 -0
  8. package/android/settings.gradle +2 -0
  9. package/android/src/main/AndroidManifest.xml +34 -0
  10. package/android/src/main/java/com/aoneahsan/nativeupdate/AppReviewPlugin.kt +153 -0
  11. package/android/src/main/java/com/aoneahsan/nativeupdate/AppUpdatePlugin.kt +275 -0
  12. package/android/src/main/java/com/aoneahsan/nativeupdate/BackgroundNotificationManager.kt +390 -0
  13. package/android/src/main/java/com/aoneahsan/nativeupdate/BackgroundUpdateManager.kt +46 -0
  14. package/android/src/main/java/com/aoneahsan/nativeupdate/BackgroundUpdatePlugin.kt +333 -0
  15. package/android/src/main/java/com/aoneahsan/nativeupdate/BackgroundUpdateWorker.kt +251 -0
  16. package/android/src/main/java/com/aoneahsan/nativeupdate/CapacitorNativeUpdatePlugin.kt +265 -0
  17. package/android/src/main/java/com/aoneahsan/nativeupdate/LiveUpdatePlugin.kt +526 -0
  18. package/android/src/main/java/com/aoneahsan/nativeupdate/NotificationActionReceiver.kt +99 -0
  19. package/android/src/main/java/com/aoneahsan/nativeupdate/SecurityManager.kt +249 -0
  20. package/dist/esm/__tests__/bundle-manager.test.d.ts +1 -0
  21. package/dist/esm/__tests__/bundle-manager.test.js +123 -0
  22. package/dist/esm/__tests__/bundle-manager.test.js.map +1 -0
  23. package/dist/esm/__tests__/config.test.d.ts +1 -0
  24. package/dist/esm/__tests__/config.test.js +69 -0
  25. package/dist/esm/__tests__/config.test.js.map +1 -0
  26. package/dist/esm/__tests__/integration.test.d.ts +1 -0
  27. package/dist/esm/__tests__/integration.test.js +78 -0
  28. package/dist/esm/__tests__/integration.test.js.map +1 -0
  29. package/dist/esm/__tests__/security.test.d.ts +1 -0
  30. package/dist/esm/__tests__/security.test.js +54 -0
  31. package/dist/esm/__tests__/security.test.js.map +1 -0
  32. package/dist/esm/__tests__/version-manager.test.d.ts +1 -0
  33. package/dist/esm/__tests__/version-manager.test.js +45 -0
  34. package/dist/esm/__tests__/version-manager.test.js.map +1 -0
  35. package/dist/esm/app-review/app-review-manager.d.ts +24 -0
  36. package/dist/esm/app-review/app-review-manager.js +195 -0
  37. package/dist/esm/app-review/app-review-manager.js.map +1 -0
  38. package/dist/esm/app-review/index.d.ts +5 -0
  39. package/dist/esm/app-review/index.js +6 -0
  40. package/dist/esm/app-review/index.js.map +1 -0
  41. package/dist/esm/app-review/platform-review-handler.d.ts +20 -0
  42. package/dist/esm/app-review/platform-review-handler.js +138 -0
  43. package/dist/esm/app-review/platform-review-handler.js.map +1 -0
  44. package/dist/esm/app-review/review-conditions-checker.d.ts +22 -0
  45. package/dist/esm/app-review/review-conditions-checker.js +155 -0
  46. package/dist/esm/app-review/review-conditions-checker.js.map +1 -0
  47. package/dist/esm/app-review/review-rate-limiter.d.ts +23 -0
  48. package/dist/esm/app-review/review-rate-limiter.js +164 -0
  49. package/dist/esm/app-review/review-rate-limiter.js.map +1 -0
  50. package/dist/esm/app-review/types.d.ts +41 -0
  51. package/dist/esm/app-review/types.js +2 -0
  52. package/dist/esm/app-review/types.js.map +1 -0
  53. package/dist/esm/app-update/app-update-checker.d.ts +13 -0
  54. package/dist/esm/app-update/app-update-checker.js +104 -0
  55. package/dist/esm/app-update/app-update-checker.js.map +1 -0
  56. package/dist/esm/app-update/app-update-installer.d.ts +19 -0
  57. package/dist/esm/app-update/app-update-installer.js +123 -0
  58. package/dist/esm/app-update/app-update-installer.js.map +1 -0
  59. package/dist/esm/app-update/app-update-manager.d.ts +28 -0
  60. package/dist/esm/app-update/app-update-manager.js +199 -0
  61. package/dist/esm/app-update/app-update-manager.js.map +1 -0
  62. package/dist/esm/app-update/app-update-notifier.d.ts +14 -0
  63. package/dist/esm/app-update/app-update-notifier.js +100 -0
  64. package/dist/esm/app-update/app-update-notifier.js.map +1 -0
  65. package/dist/esm/app-update/index.d.ts +6 -0
  66. package/dist/esm/app-update/index.js +7 -0
  67. package/dist/esm/app-update/index.js.map +1 -0
  68. package/dist/esm/app-update/platform-app-update.d.ts +19 -0
  69. package/dist/esm/app-update/platform-app-update.js +129 -0
  70. package/dist/esm/app-update/platform-app-update.js.map +1 -0
  71. package/dist/esm/app-update/types.d.ts +58 -0
  72. package/dist/esm/app-update/types.js +12 -0
  73. package/dist/esm/app-update/types.js.map +1 -0
  74. package/dist/esm/background-update/background-scheduler.d.ts +17 -0
  75. package/dist/esm/background-update/background-scheduler.js +195 -0
  76. package/dist/esm/background-update/background-scheduler.js.map +1 -0
  77. package/dist/esm/background-update/index.d.ts +3 -0
  78. package/dist/esm/background-update/index.js +3 -0
  79. package/dist/esm/background-update/index.js.map +1 -0
  80. package/dist/esm/background-update/notification-manager.d.ts +29 -0
  81. package/dist/esm/background-update/notification-manager.js +89 -0
  82. package/dist/esm/background-update/notification-manager.js.map +1 -0
  83. package/dist/esm/core/analytics.d.ts +70 -0
  84. package/dist/esm/core/analytics.js +137 -0
  85. package/dist/esm/core/analytics.js.map +1 -0
  86. package/dist/esm/core/cache-manager.d.ts +72 -0
  87. package/dist/esm/core/cache-manager.js +275 -0
  88. package/dist/esm/core/cache-manager.js.map +1 -0
  89. package/dist/esm/core/config.d.ts +48 -0
  90. package/dist/esm/core/config.js +83 -0
  91. package/dist/esm/core/config.js.map +1 -0
  92. package/dist/esm/core/errors.d.ts +51 -0
  93. package/dist/esm/core/errors.js +80 -0
  94. package/dist/esm/core/errors.js.map +1 -0
  95. package/dist/esm/core/logger.d.ts +21 -0
  96. package/dist/esm/core/logger.js +109 -0
  97. package/dist/esm/core/logger.js.map +1 -0
  98. package/dist/esm/core/performance.d.ts +53 -0
  99. package/dist/esm/core/performance.js +140 -0
  100. package/dist/esm/core/performance.js.map +1 -0
  101. package/dist/esm/core/plugin-manager.d.ts +66 -0
  102. package/dist/esm/core/plugin-manager.js +148 -0
  103. package/dist/esm/core/plugin-manager.js.map +1 -0
  104. package/dist/esm/core/security.d.ts +93 -0
  105. package/dist/esm/core/security.js +315 -0
  106. package/dist/esm/core/security.js.map +1 -0
  107. package/dist/esm/definitions.d.ts +639 -0
  108. package/dist/esm/definitions.js +103 -0
  109. package/dist/esm/definitions.js.map +1 -0
  110. package/dist/esm/index.d.ts +12 -0
  111. package/dist/esm/index.js +16 -0
  112. package/dist/esm/index.js.map +1 -0
  113. package/dist/esm/live-update/bundle-manager.d.ts +94 -0
  114. package/dist/esm/live-update/bundle-manager.js +310 -0
  115. package/dist/esm/live-update/bundle-manager.js.map +1 -0
  116. package/dist/esm/live-update/certificate-pinning.d.ts +38 -0
  117. package/dist/esm/live-update/certificate-pinning.js +78 -0
  118. package/dist/esm/live-update/certificate-pinning.js.map +1 -0
  119. package/dist/esm/live-update/download-manager.d.ts +67 -0
  120. package/dist/esm/live-update/download-manager.js +319 -0
  121. package/dist/esm/live-update/download-manager.js.map +1 -0
  122. package/dist/esm/live-update/update-manager.d.ts +52 -0
  123. package/dist/esm/live-update/update-manager.js +294 -0
  124. package/dist/esm/live-update/update-manager.js.map +1 -0
  125. package/dist/esm/live-update/version-manager.d.ts +84 -0
  126. package/dist/esm/live-update/version-manager.js +335 -0
  127. package/dist/esm/live-update/version-manager.js.map +1 -0
  128. package/dist/esm/plugin.d.ts +6 -0
  129. package/dist/esm/plugin.js +283 -0
  130. package/dist/esm/plugin.js.map +1 -0
  131. package/dist/esm/security/crypto.d.ts +25 -0
  132. package/dist/esm/security/crypto.js +70 -0
  133. package/dist/esm/security/crypto.js.map +1 -0
  134. package/dist/esm/security/validator.d.ts +60 -0
  135. package/dist/esm/security/validator.js +143 -0
  136. package/dist/esm/security/validator.js.map +1 -0
  137. package/dist/esm/web.d.ts +74 -0
  138. package/dist/esm/web.js +595 -0
  139. package/dist/esm/web.js.map +1 -0
  140. package/dist/plugin.cjs.js +2 -0
  141. package/dist/plugin.cjs.js.map +1 -0
  142. package/dist/plugin.esm.js +2 -0
  143. package/dist/plugin.esm.js.map +1 -0
  144. package/dist/plugin.js +3 -0
  145. package/dist/plugin.js.map +1 -0
  146. package/docs/APP_REVIEW_GUIDE.md +768 -0
  147. package/docs/BUNDLE_SIGNING.md +264 -0
  148. package/docs/LIVE_UPDATES_GUIDE.md +650 -0
  149. package/docs/MIGRATION.md +192 -0
  150. package/docs/NATIVE_UPDATES_GUIDE.md +694 -0
  151. package/docs/QUICK_START.md +606 -0
  152. package/docs/README.md +111 -0
  153. package/docs/REMAINING_FEATURES.md +139 -0
  154. package/docs/api/app-review-api.md +259 -0
  155. package/docs/api/app-update-api.md +238 -0
  156. package/docs/api/events-api.md +451 -0
  157. package/docs/api/live-update-api.md +265 -0
  158. package/docs/background-updates.md +392 -0
  159. package/docs/examples/advanced-scenarios.md +410 -0
  160. package/docs/examples/basic-usage.md +185 -0
  161. package/docs/features/app-reviews.md +975 -0
  162. package/docs/features/app-updates.md +785 -0
  163. package/docs/features/live-updates.md +633 -0
  164. package/docs/getting-started/configuration.md +468 -0
  165. package/docs/getting-started/installation.md +209 -0
  166. package/docs/getting-started/quick-start.md +379 -0
  167. package/docs/guides/deployment-guide.md +333 -0
  168. package/docs/guides/migration-from-codepush.md +142 -0
  169. package/docs/guides/security-best-practices.md +1057 -0
  170. package/docs/guides/testing-guide.md +373 -0
  171. package/docs/production-readiness.md +478 -0
  172. package/docs/security/certificate-pinning.md +122 -0
  173. package/docs/server-requirements.md +147 -0
  174. package/ios/Plugin/AppReview/AppReviewPlugin.swift +158 -0
  175. package/ios/Plugin/AppUpdate/AppUpdatePlugin.swift +234 -0
  176. package/ios/Plugin/BackgroundUpdate/BackgroundNotificationManager.swift +329 -0
  177. package/ios/Plugin/BackgroundUpdate/BackgroundUpdatePlugin.swift +396 -0
  178. package/ios/Plugin/CapacitorNativeUpdatePlugin.m +45 -0
  179. package/ios/Plugin/CapacitorNativeUpdatePlugin.swift +190 -0
  180. package/ios/Plugin/Info.plist +43 -0
  181. package/ios/Plugin/LiveUpdate/LiveUpdatePlugin.swift +689 -0
  182. package/ios/Plugin/LiveUpdate/WebViewConfiguration.swift +45 -0
  183. package/ios/Plugin/Security/SecurityManager.swift +289 -0
  184. package/package.json +90 -0
@@ -0,0 +1,396 @@
1
+ import Foundation
2
+ import Capacitor
3
+ import BackgroundTasks
4
+ import UserNotifications
5
+
6
+ @objc(BackgroundUpdatePlugin)
7
+ public class BackgroundUpdatePlugin: CAPPlugin {
8
+
9
+ private let backgroundTaskIdentifier = "com.aoneahsan.nativeupdate.background"
10
+ private var backgroundUpdateConfig: BackgroundUpdateConfig?
11
+ private var backgroundUpdateStatus: BackgroundUpdateStatus
12
+ private var notificationManager: BackgroundNotificationManager?
13
+
14
+ public override func load() {
15
+ super.load()
16
+
17
+ // Initialize background update status
18
+ backgroundUpdateStatus = BackgroundUpdateStatus(
19
+ enabled: false,
20
+ isRunning: false,
21
+ checkCount: 0,
22
+ failureCount: 0
23
+ )
24
+
25
+ // Initialize notification manager
26
+ notificationManager = BackgroundNotificationManager(plugin: self)
27
+
28
+ // Register background task
29
+ if #available(iOS 13.0, *) {
30
+ BGTaskScheduler.shared.register(forTaskWithIdentifier: backgroundTaskIdentifier, using: nil) { task in
31
+ self.handleBackgroundTask(task: task as! BGAppRefreshTask)
32
+ }
33
+ }
34
+ }
35
+
36
+ @objc func enableBackgroundUpdates(_ call: CAPPluginCall) {
37
+ guard let configData = call.options else {
38
+ call.reject("Missing configuration")
39
+ return
40
+ }
41
+
42
+ do {
43
+ let config = try BackgroundUpdateConfig.from(configData)
44
+ backgroundUpdateConfig = config
45
+ backgroundUpdateStatus.enabled = config.enabled
46
+
47
+ if config.enabled {
48
+ scheduleBackgroundTask(interval: config.checkInterval)
49
+ } else {
50
+ disableBackgroundUpdates()
51
+ }
52
+
53
+ call.resolve()
54
+ } catch {
55
+ call.reject("Invalid configuration: \(error.localizedDescription)")
56
+ }
57
+ }
58
+
59
+ @objc func disableBackgroundUpdates(_ call: CAPPluginCall) {
60
+ disableBackgroundUpdates()
61
+ call.resolve()
62
+ }
63
+
64
+ @objc func getBackgroundUpdateStatus(_ call: CAPPluginCall) {
65
+ call.resolve(backgroundUpdateStatus.toDictionary())
66
+ }
67
+
68
+ @objc func scheduleBackgroundCheck(_ call: CAPPluginCall) {
69
+ guard let interval = call.getDouble("interval") else {
70
+ call.reject("Missing interval parameter")
71
+ return
72
+ }
73
+
74
+ scheduleBackgroundTask(interval: Int(interval))
75
+ call.resolve()
76
+ }
77
+
78
+ @objc func triggerBackgroundCheck(_ call: CAPPluginCall) {
79
+ Task {
80
+ let result = await performBackgroundCheck()
81
+ call.resolve(result.toDictionary())
82
+ }
83
+ }
84
+
85
+ @objc func setNotificationPreferences(_ call: CAPPluginCall) {
86
+ guard let preferences = call.options else {
87
+ call.reject("Missing preferences")
88
+ return
89
+ }
90
+
91
+ notificationManager?.setPreferences(preferences)
92
+ call.resolve()
93
+ }
94
+
95
+ @objc func getNotificationPermissions(_ call: CAPPluginCall) {
96
+ notificationManager?.getPermissionStatus { status in
97
+ call.resolve(status.toDictionary())
98
+ }
99
+ }
100
+
101
+ @objc func requestNotificationPermissions(_ call: CAPPluginCall) {
102
+ notificationManager?.requestPermissions { granted in
103
+ call.resolve(["granted": granted])
104
+ }
105
+ }
106
+
107
+ // MARK: - Private Methods
108
+
109
+ private func disableBackgroundUpdates() {
110
+ backgroundUpdateStatus.enabled = false
111
+ backgroundUpdateStatus.isRunning = false
112
+ backgroundUpdateStatus.currentTaskId = nil
113
+
114
+ if #available(iOS 13.0, *) {
115
+ BGTaskScheduler.shared.cancel(taskRequestWithIdentifier: backgroundTaskIdentifier)
116
+ }
117
+ }
118
+
119
+ private func scheduleBackgroundTask(interval: Int) {
120
+ guard #available(iOS 13.0, *) else {
121
+ NSLog("BackgroundTasks framework not available on iOS < 13.0")
122
+ return
123
+ }
124
+
125
+ let request = BGAppRefreshTaskRequest(identifier: backgroundTaskIdentifier)
126
+ request.earliestBeginDate = Date(timeIntervalSinceNow: TimeInterval(interval / 1000))
127
+
128
+ do {
129
+ try BGTaskScheduler.shared.submit(request)
130
+ backgroundUpdateStatus.nextCheckTime = Int(Date().timeIntervalSince1970 * 1000) + interval
131
+ NSLog("Background task scheduled for \(interval)ms from now")
132
+ } catch {
133
+ NSLog("Failed to schedule background task: \(error.localizedDescription)")
134
+ }
135
+ }
136
+
137
+ @available(iOS 13.0, *)
138
+ private func handleBackgroundTask(task: BGAppRefreshTask) {
139
+ NSLog("Background task started")
140
+
141
+ // Schedule next task
142
+ if let config = backgroundUpdateConfig {
143
+ scheduleBackgroundTask(interval: config.checkInterval)
144
+ }
145
+
146
+ // Set expiration handler
147
+ task.expirationHandler = {
148
+ NSLog("Background task expired")
149
+ self.backgroundUpdateStatus.isRunning = false
150
+ task.setTaskCompleted(success: false)
151
+ }
152
+
153
+ // Perform background check
154
+ Task {
155
+ let result = await performBackgroundCheck()
156
+
157
+ // Notify listeners
158
+ await MainActor.run {
159
+ self.notifyListeners("backgroundUpdateProgress", data: [
160
+ "type": result.appUpdate != nil ? "app_update" : "live_update",
161
+ "status": result.success ? "completed" : "failed",
162
+ "percent": 100
163
+ ])
164
+ }
165
+
166
+ task.setTaskCompleted(success: result.success)
167
+ }
168
+ }
169
+
170
+ private func performBackgroundCheck() async -> BackgroundCheckResult {
171
+ guard let config = backgroundUpdateConfig, config.enabled else {
172
+ return BackgroundCheckResult(
173
+ success: false,
174
+ updatesFound: false,
175
+ notificationSent: false,
176
+ error: UpdateError(code: "INVALID_CONFIG", message: "Background updates not enabled")
177
+ )
178
+ }
179
+
180
+ backgroundUpdateStatus.isRunning = true
181
+ backgroundUpdateStatus.checkCount += 1
182
+ backgroundUpdateStatus.lastCheckTime = Int(Date().timeIntervalSince1970 * 1000)
183
+
184
+ do {
185
+ var appUpdate: AppUpdateInfo?
186
+ var liveUpdate: LatestVersion?
187
+
188
+ // Check for app updates
189
+ if config.updateTypes.contains(.appUpdate) || config.updateTypes.contains(.both) {
190
+ appUpdate = await checkForAppUpdate()
191
+ }
192
+
193
+ // Check for live updates
194
+ if config.updateTypes.contains(.liveUpdate) || config.updateTypes.contains(.both) {
195
+ liveUpdate = await checkForLiveUpdate()
196
+ }
197
+
198
+ let updatesFound = (appUpdate?.updateAvailable ?? false) || (liveUpdate?.available ?? false)
199
+ var notificationSent = false
200
+
201
+ if updatesFound {
202
+ notificationSent = await sendNotification(appUpdate: appUpdate, liveUpdate: liveUpdate)
203
+ }
204
+
205
+ backgroundUpdateStatus.isRunning = false
206
+ backgroundUpdateStatus.lastError = nil
207
+
208
+ if updatesFound {
209
+ backgroundUpdateStatus.lastUpdateTime = Int(Date().timeIntervalSince1970 * 1000)
210
+ }
211
+
212
+ return BackgroundCheckResult(
213
+ success: true,
214
+ updatesFound: updatesFound,
215
+ appUpdate: appUpdate,
216
+ liveUpdate: liveUpdate,
217
+ notificationSent: notificationSent
218
+ )
219
+
220
+ } catch {
221
+ backgroundUpdateStatus.isRunning = false
222
+ backgroundUpdateStatus.failureCount += 1
223
+
224
+ let updateError = UpdateError(
225
+ code: "UNKNOWN_ERROR",
226
+ message: error.localizedDescription
227
+ )
228
+ backgroundUpdateStatus.lastError = updateError
229
+
230
+ return BackgroundCheckResult(
231
+ success: false,
232
+ updatesFound: false,
233
+ notificationSent: false,
234
+ error: updateError
235
+ )
236
+ }
237
+ }
238
+
239
+ private func checkForAppUpdate() async -> AppUpdateInfo? {
240
+ // Create an instance of AppUpdatePlugin to check for updates
241
+ let appUpdatePlugin = AppUpdatePlugin(plugin: self)
242
+ return await appUpdatePlugin.getAppUpdateInfoAsync()
243
+ }
244
+
245
+ private func checkForLiveUpdate() async -> LatestVersion? {
246
+ // Create an instance of LiveUpdatePlugin to check for updates
247
+ let liveUpdatePlugin = LiveUpdatePlugin(plugin: self)
248
+ return await liveUpdatePlugin.getLatestVersionAsync()
249
+ }
250
+
251
+ private func sendNotification(appUpdate: AppUpdateInfo?, liveUpdate: LatestVersion?) async -> Bool {
252
+ guard let notificationManager = notificationManager else {
253
+ return false
254
+ }
255
+
256
+ return await notificationManager.sendUpdateNotification(
257
+ appUpdate: appUpdate,
258
+ liveUpdate: liveUpdate
259
+ )
260
+ }
261
+ }
262
+
263
+ // MARK: - Data Models
264
+
265
+ struct BackgroundUpdateConfig {
266
+ let enabled: Bool
267
+ let checkInterval: Int
268
+ let updateTypes: [BackgroundUpdateType]
269
+ let autoInstall: Bool
270
+ let notificationPreferences: NotificationPreferences?
271
+ let respectBatteryOptimization: Bool
272
+ let allowMeteredConnection: Bool
273
+ let minimumBatteryLevel: Int
274
+ let requireWifi: Bool
275
+ let maxRetries: Int
276
+ let retryDelay: Int
277
+ let taskIdentifier: String?
278
+
279
+ static func from(_ obj: [String: Any]) throws -> BackgroundUpdateConfig {
280
+ guard let enabled = obj["enabled"] as? Bool,
281
+ let checkInterval = obj["checkInterval"] as? Int,
282
+ let updateTypesArray = obj["updateTypes"] as? [String] else {
283
+ throw NSError(domain: "BackgroundUpdateConfig", code: 1, userInfo: [NSLocalizedDescriptionKey: "Missing required fields"])
284
+ }
285
+
286
+ let updateTypes = updateTypesArray.compactMap { BackgroundUpdateType(rawValue: $0) }
287
+ let notificationPreferences = obj["notificationPreferences"] as? [String: Any]
288
+
289
+ return BackgroundUpdateConfig(
290
+ enabled: enabled,
291
+ checkInterval: checkInterval,
292
+ updateTypes: updateTypes,
293
+ autoInstall: obj["autoInstall"] as? Bool ?? false,
294
+ notificationPreferences: notificationPreferences != nil ? NotificationPreferences.from(notificationPreferences!) : nil,
295
+ respectBatteryOptimization: obj["respectBatteryOptimization"] as? Bool ?? true,
296
+ allowMeteredConnection: obj["allowMeteredConnection"] as? Bool ?? false,
297
+ minimumBatteryLevel: obj["minimumBatteryLevel"] as? Int ?? 20,
298
+ requireWifi: obj["requireWifi"] as? Bool ?? false,
299
+ maxRetries: obj["maxRetries"] as? Int ?? 3,
300
+ retryDelay: obj["retryDelay"] as? Int ?? 5000,
301
+ taskIdentifier: obj["taskIdentifier"] as? String
302
+ )
303
+ }
304
+ }
305
+
306
+ enum BackgroundUpdateType: String, CaseIterable {
307
+ case appUpdate = "app_update"
308
+ case liveUpdate = "live_update"
309
+ case both = "both"
310
+ }
311
+
312
+ struct BackgroundUpdateStatus {
313
+ var enabled: Bool
314
+ var lastCheckTime: Int?
315
+ var nextCheckTime: Int?
316
+ var lastUpdateTime: Int?
317
+ var currentTaskId: String?
318
+ var isRunning: Bool
319
+ var checkCount: Int
320
+ var failureCount: Int
321
+ var lastError: UpdateError?
322
+
323
+ func toDictionary() -> [String: Any] {
324
+ var obj: [String: Any] = [
325
+ "enabled": enabled,
326
+ "isRunning": isRunning,
327
+ "checkCount": checkCount,
328
+ "failureCount": failureCount
329
+ ]
330
+
331
+ if let lastCheckTime = lastCheckTime {
332
+ obj["lastCheckTime"] = lastCheckTime
333
+ }
334
+
335
+ if let nextCheckTime = nextCheckTime {
336
+ obj["nextCheckTime"] = nextCheckTime
337
+ }
338
+
339
+ if let lastUpdateTime = lastUpdateTime {
340
+ obj["lastUpdateTime"] = lastUpdateTime
341
+ }
342
+
343
+ if let currentTaskId = currentTaskId {
344
+ obj["currentTaskId"] = currentTaskId
345
+ }
346
+
347
+ if let lastError = lastError {
348
+ obj["lastError"] = lastError.toDictionary()
349
+ }
350
+
351
+ return obj
352
+ }
353
+ }
354
+
355
+ struct BackgroundCheckResult {
356
+ let success: Bool
357
+ let updatesFound: Bool
358
+ let appUpdate: AppUpdateInfo?
359
+ let liveUpdate: LatestVersion?
360
+ let notificationSent: Bool
361
+ let error: UpdateError?
362
+
363
+ func toDictionary() -> [String: Any] {
364
+ var obj: [String: Any] = [
365
+ "success": success,
366
+ "updatesFound": updatesFound,
367
+ "notificationSent": notificationSent
368
+ ]
369
+
370
+ if let appUpdate = appUpdate {
371
+ obj["appUpdate"] = appUpdate.toDictionary()
372
+ }
373
+
374
+ if let liveUpdate = liveUpdate {
375
+ obj["liveUpdate"] = liveUpdate.toDictionary()
376
+ }
377
+
378
+ if let error = error {
379
+ obj["error"] = error.toDictionary()
380
+ }
381
+
382
+ return obj
383
+ }
384
+ }
385
+
386
+ struct UpdateError {
387
+ let code: String
388
+ let message: String
389
+
390
+ func toDictionary() -> [String: Any] {
391
+ return [
392
+ "code": code,
393
+ "message": message
394
+ ]
395
+ }
396
+ }
@@ -0,0 +1,45 @@
1
+ #import <Foundation/Foundation.h>
2
+ #import <Capacitor/Capacitor.h>
3
+
4
+ // Define the plugin using the CAP_PLUGIN Macro, and
5
+ // each method the plugin supports using the CAP_PLUGIN_METHOD macro.
6
+ CAP_PLUGIN(NativeUpdatePlugin, "CapacitorNativeUpdate",
7
+ CAP_PLUGIN_METHOD(configure, CAPPluginReturnPromise);
8
+ CAP_PLUGIN_METHOD(getSecurityInfo, CAPPluginReturnPromise);
9
+
10
+ // Live Update Methods
11
+ CAP_PLUGIN_METHOD(sync, CAPPluginReturnPromise);
12
+ CAP_PLUGIN_METHOD(download, CAPPluginReturnPromise);
13
+ CAP_PLUGIN_METHOD(set, CAPPluginReturnPromise);
14
+ CAP_PLUGIN_METHOD(reload, CAPPluginReturnPromise);
15
+ CAP_PLUGIN_METHOD(reset, CAPPluginReturnPromise);
16
+ CAP_PLUGIN_METHOD(current, CAPPluginReturnPromise);
17
+ CAP_PLUGIN_METHOD(list, CAPPluginReturnPromise);
18
+ CAP_PLUGIN_METHOD(delete, CAPPluginReturnPromise);
19
+ CAP_PLUGIN_METHOD(notifyAppReady, CAPPluginReturnPromise);
20
+ CAP_PLUGIN_METHOD(getLatest, CAPPluginReturnPromise);
21
+ CAP_PLUGIN_METHOD(setChannel, CAPPluginReturnPromise);
22
+ CAP_PLUGIN_METHOD(setUpdateUrl, CAPPluginReturnPromise);
23
+ CAP_PLUGIN_METHOD(validateUpdate, CAPPluginReturnPromise);
24
+
25
+ // App Update Methods
26
+ CAP_PLUGIN_METHOD(getAppUpdateInfo, CAPPluginReturnPromise);
27
+ CAP_PLUGIN_METHOD(performImmediateUpdate, CAPPluginReturnPromise);
28
+ CAP_PLUGIN_METHOD(startFlexibleUpdate, CAPPluginReturnPromise);
29
+ CAP_PLUGIN_METHOD(completeFlexibleUpdate, CAPPluginReturnPromise);
30
+ CAP_PLUGIN_METHOD(openAppStore, CAPPluginReturnPromise);
31
+
32
+ // App Review Methods
33
+ CAP_PLUGIN_METHOD(requestReview, CAPPluginReturnPromise);
34
+ CAP_PLUGIN_METHOD(canRequestReview, CAPPluginReturnPromise);
35
+
36
+ // Background Update Methods
37
+ CAP_PLUGIN_METHOD(enableBackgroundUpdates, CAPPluginReturnPromise);
38
+ CAP_PLUGIN_METHOD(disableBackgroundUpdates, CAPPluginReturnPromise);
39
+ CAP_PLUGIN_METHOD(getBackgroundUpdateStatus, CAPPluginReturnPromise);
40
+ CAP_PLUGIN_METHOD(scheduleBackgroundCheck, CAPPluginReturnPromise);
41
+ CAP_PLUGIN_METHOD(triggerBackgroundCheck, CAPPluginReturnPromise);
42
+ CAP_PLUGIN_METHOD(setNotificationPreferences, CAPPluginReturnPromise);
43
+ CAP_PLUGIN_METHOD(getNotificationPermissions, CAPPluginReturnPromise);
44
+ CAP_PLUGIN_METHOD(requestNotificationPermissions, CAPPluginReturnPromise);
45
+ )
@@ -0,0 +1,190 @@
1
+ import Foundation
2
+ import Capacitor
3
+
4
+ @objc(NativeUpdatePlugin)
5
+ public class NativeUpdatePlugin: CAPPlugin {
6
+ private var liveUpdatePlugin: LiveUpdatePlugin!
7
+ private var appUpdatePlugin: AppUpdatePlugin!
8
+ private var appReviewPlugin: AppReviewPlugin!
9
+ private var backgroundUpdatePlugin: BackgroundUpdatePlugin!
10
+ private var securityManager: SecurityManager!
11
+
12
+ override public func load() {
13
+ super.load()
14
+
15
+ // Initialize sub-plugins
16
+ liveUpdatePlugin = LiveUpdatePlugin(plugin: self)
17
+ appUpdatePlugin = AppUpdatePlugin(plugin: self)
18
+ appReviewPlugin = AppReviewPlugin(plugin: self)
19
+ backgroundUpdatePlugin = BackgroundUpdatePlugin()
20
+ securityManager = SecurityManager()
21
+
22
+ // Set up listeners
23
+ liveUpdatePlugin.setProgressListener { [weak self] progress in
24
+ self?.notifyListeners("downloadProgress", data: progress)
25
+ }
26
+
27
+ liveUpdatePlugin.setStateChangeListener { [weak self] state in
28
+ self?.notifyListeners("updateStateChanged", data: state)
29
+ }
30
+ }
31
+
32
+ @objc func configure(_ call: CAPPluginCall) {
33
+ guard let config = call.getObject("config") else {
34
+ call.reject("Configuration object is required")
35
+ return
36
+ }
37
+
38
+ do {
39
+ // Validate security settings
40
+ if let securityConfig = config["security"] as? [String: Any] {
41
+ try securityManager.configure(securityConfig)
42
+ }
43
+
44
+ // Configure sub-plugins
45
+ if let liveUpdateConfig = config["liveUpdate"] as? [String: Any] {
46
+ try liveUpdatePlugin.configure(liveUpdateConfig)
47
+ }
48
+
49
+ if let appUpdateConfig = config["appUpdate"] as? [String: Any] {
50
+ try appUpdatePlugin.configure(appUpdateConfig)
51
+ }
52
+
53
+ if let appReviewConfig = config["appReview"] as? [String: Any] {
54
+ try appReviewPlugin.configure(appReviewConfig)
55
+ }
56
+
57
+ if let backgroundUpdateConfig = config["backgroundUpdate"] as? [String: Any] {
58
+ try backgroundUpdatePlugin.configure(backgroundUpdateConfig)
59
+ }
60
+
61
+ call.resolve()
62
+ } catch {
63
+ call.reject("Configuration failed", error.localizedDescription)
64
+ }
65
+ }
66
+
67
+ @objc func getSecurityInfo(_ call: CAPPluginCall) {
68
+ call.resolve(securityManager.getSecurityInfo())
69
+ }
70
+
71
+ // MARK: - Live Update Methods
72
+
73
+ @objc func sync(_ call: CAPPluginCall) {
74
+ liveUpdatePlugin.sync(call)
75
+ }
76
+
77
+ @objc func download(_ call: CAPPluginCall) {
78
+ liveUpdatePlugin.download(call)
79
+ }
80
+
81
+ @objc func set(_ call: CAPPluginCall) {
82
+ liveUpdatePlugin.set(call)
83
+ }
84
+
85
+ @objc func reload(_ call: CAPPluginCall) {
86
+ liveUpdatePlugin.reload(call)
87
+ }
88
+
89
+ @objc func reset(_ call: CAPPluginCall) {
90
+ liveUpdatePlugin.reset(call)
91
+ }
92
+
93
+ @objc func current(_ call: CAPPluginCall) {
94
+ liveUpdatePlugin.current(call)
95
+ }
96
+
97
+ @objc func list(_ call: CAPPluginCall) {
98
+ liveUpdatePlugin.list(call)
99
+ }
100
+
101
+ @objc func delete(_ call: CAPPluginCall) {
102
+ liveUpdatePlugin.delete(call)
103
+ }
104
+
105
+ @objc func notifyAppReady(_ call: CAPPluginCall) {
106
+ liveUpdatePlugin.notifyAppReady(call)
107
+ }
108
+
109
+ @objc func getLatest(_ call: CAPPluginCall) {
110
+ liveUpdatePlugin.getLatest(call)
111
+ }
112
+
113
+ @objc func setChannel(_ call: CAPPluginCall) {
114
+ liveUpdatePlugin.setChannel(call)
115
+ }
116
+
117
+ @objc func setUpdateUrl(_ call: CAPPluginCall) {
118
+ liveUpdatePlugin.setUpdateUrl(call)
119
+ }
120
+
121
+ @objc func validateUpdate(_ call: CAPPluginCall) {
122
+ liveUpdatePlugin.validateUpdate(call)
123
+ }
124
+
125
+ // MARK: - App Update Methods
126
+
127
+ @objc func getAppUpdateInfo(_ call: CAPPluginCall) {
128
+ appUpdatePlugin.getAppUpdateInfo(call)
129
+ }
130
+
131
+ @objc func performImmediateUpdate(_ call: CAPPluginCall) {
132
+ appUpdatePlugin.performImmediateUpdate(call)
133
+ }
134
+
135
+ @objc func startFlexibleUpdate(_ call: CAPPluginCall) {
136
+ appUpdatePlugin.startFlexibleUpdate(call)
137
+ }
138
+
139
+ @objc func completeFlexibleUpdate(_ call: CAPPluginCall) {
140
+ appUpdatePlugin.completeFlexibleUpdate(call)
141
+ }
142
+
143
+ @objc func openAppStore(_ call: CAPPluginCall) {
144
+ appUpdatePlugin.openAppStore(call)
145
+ }
146
+
147
+ // MARK: - App Review Methods
148
+
149
+ @objc func requestReview(_ call: CAPPluginCall) {
150
+ appReviewPlugin.requestReview(call)
151
+ }
152
+
153
+ @objc func canRequestReview(_ call: CAPPluginCall) {
154
+ appReviewPlugin.canRequestReview(call)
155
+ }
156
+
157
+ // MARK: - Background Update Methods
158
+
159
+ @objc func enableBackgroundUpdates(_ call: CAPPluginCall) {
160
+ backgroundUpdatePlugin.enableBackgroundUpdates(call)
161
+ }
162
+
163
+ @objc func disableBackgroundUpdates(_ call: CAPPluginCall) {
164
+ backgroundUpdatePlugin.disableBackgroundUpdates(call)
165
+ }
166
+
167
+ @objc func getBackgroundUpdateStatus(_ call: CAPPluginCall) {
168
+ backgroundUpdatePlugin.getBackgroundUpdateStatus(call)
169
+ }
170
+
171
+ @objc func scheduleBackgroundCheck(_ call: CAPPluginCall) {
172
+ backgroundUpdatePlugin.scheduleBackgroundCheck(call)
173
+ }
174
+
175
+ @objc func triggerBackgroundCheck(_ call: CAPPluginCall) {
176
+ backgroundUpdatePlugin.triggerBackgroundCheck(call)
177
+ }
178
+
179
+ @objc func setNotificationPreferences(_ call: CAPPluginCall) {
180
+ backgroundUpdatePlugin.setNotificationPreferences(call)
181
+ }
182
+
183
+ @objc func getNotificationPermissions(_ call: CAPPluginCall) {
184
+ backgroundUpdatePlugin.getNotificationPermissions(call)
185
+ }
186
+
187
+ @objc func requestNotificationPermissions(_ call: CAPPluginCall) {
188
+ backgroundUpdatePlugin.requestNotificationPermissions(call)
189
+ }
190
+ }
@@ -0,0 +1,43 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>CFBundleDevelopmentRegion</key>
6
+ <string>$(DEVELOPMENT_LANGUAGE)</string>
7
+ <key>CFBundleExecutable</key>
8
+ <string>$(EXECUTABLE_NAME)</string>
9
+ <key>CFBundleIdentifier</key>
10
+ <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
11
+ <key>CFBundleInfoDictionaryVersion</key>
12
+ <string>6.0</string>
13
+ <key>CFBundleName</key>
14
+ <string>$(PRODUCT_NAME)</string>
15
+ <key>CFBundlePackageType</key>
16
+ <string>FMWK</string>
17
+ <key>CFBundleShortVersionString</key>
18
+ <string>1.0</string>
19
+ <key>CFBundleVersion</key>
20
+ <string>1</string>
21
+ <key>NSAppTransportSecurity</key>
22
+ <dict>
23
+ <key>NSAllowsArbitraryLoads</key>
24
+ <false/>
25
+ <key>NSAllowsArbitraryLoadsForMedia</key>
26
+ <false/>
27
+ <key>NSAllowsArbitraryLoadsInWebContent</key>
28
+ <false/>
29
+ <key>NSAllowsLocalNetworking</key>
30
+ <false/>
31
+ </dict>
32
+ <key>UIBackgroundModes</key>
33
+ <array>
34
+ <string>background-app-refresh</string>
35
+ <string>background-processing</string>
36
+ </array>
37
+ <key>BGTaskSchedulerPermittedIdentifiers</key>
38
+ <array>
39
+ <string>com.aoneahsan.nativeupdate.background</string>
40
+ <string>com.aoneahsan.nativeupdate.processing</string>
41
+ </array>
42
+ </dict>
43
+ </plist>