native-update 1.1.0 → 1.1.2
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/android/build.gradle +5 -0
- package/android/src/main/java/com/aoneahsan/nativeupdate/AppUpdatePlugin.kt +4 -3
- package/android/src/main/java/com/aoneahsan/nativeupdate/BackgroundNotificationManager.kt +23 -11
- package/android/src/main/java/com/aoneahsan/nativeupdate/BackgroundUpdatePlugin.kt +16 -12
- package/android/src/main/java/com/aoneahsan/nativeupdate/BackgroundUpdateWorker.kt +5 -5
- package/android/src/main/java/com/aoneahsan/nativeupdate/NativeUpdatePlugin.kt +2 -4
- package/android/src/main/java/com/aoneahsan/nativeupdate/NotificationActionReceiver.kt +1 -2
- package/cli/index.js +0 -0
- package/ios/Plugin/AppUpdate/AppUpdatePlugin.swift +5 -5
- package/ios/Plugin/BackgroundUpdate/BackgroundUpdatePlugin.swift +32 -12
- package/ios/Plugin/LiveUpdate/LiveUpdatePlugin.swift +22 -22
- package/package.json +1 -1
package/android/build.gradle
CHANGED
|
@@ -71,6 +71,8 @@ dependencies {
|
|
|
71
71
|
|
|
72
72
|
// Kotlin
|
|
73
73
|
implementation 'org.jetbrains.kotlin:kotlin-stdlib:1.9.22'
|
|
74
|
+
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3'
|
|
75
|
+
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.7.3'
|
|
74
76
|
|
|
75
77
|
// AndroidX
|
|
76
78
|
implementation "androidx.appcompat:appcompat:${androidxAppCompatVersion}"
|
|
@@ -90,6 +92,9 @@ dependencies {
|
|
|
90
92
|
// Security
|
|
91
93
|
implementation 'androidx.security:security-crypto:1.1.0-alpha06'
|
|
92
94
|
|
|
95
|
+
// JSON parsing
|
|
96
|
+
implementation 'com.google.code.gson:gson:2.10.1'
|
|
97
|
+
|
|
93
98
|
// Testing
|
|
94
99
|
testImplementation 'junit:junit:4.13.2'
|
|
95
100
|
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
|
|
@@ -17,6 +17,7 @@ import com.google.android.play.core.install.model.InstallStatus
|
|
|
17
17
|
import com.google.android.play.core.install.model.UpdateAvailability
|
|
18
18
|
import com.google.android.play.core.ktx.isFlexibleUpdateAllowed
|
|
19
19
|
import com.google.android.play.core.ktx.isImmediateUpdateAllowed
|
|
20
|
+
import com.google.android.gms.tasks.Tasks
|
|
20
21
|
import kotlinx.coroutines.tasks.await
|
|
21
22
|
|
|
22
23
|
class AppUpdatePlugin(
|
|
@@ -251,18 +252,18 @@ class AppUpdatePlugin(
|
|
|
251
252
|
}
|
|
252
253
|
|
|
253
254
|
// Async method for background update checks
|
|
254
|
-
suspend fun getAppUpdateInfoAsync():
|
|
255
|
+
suspend fun getAppUpdateInfoAsync(): AppUpdateStatus? {
|
|
255
256
|
return try {
|
|
256
257
|
val appUpdateInfo = appUpdateManager.appUpdateInfo.await()
|
|
257
258
|
|
|
258
259
|
if (appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE) {
|
|
259
|
-
|
|
260
|
+
AppUpdateStatus(
|
|
260
261
|
updateAvailable = true,
|
|
261
262
|
currentVersion = getCurrentAppVersion(),
|
|
262
263
|
availableVersion = appUpdateInfo.availableVersionCode().toString()
|
|
263
264
|
)
|
|
264
265
|
} else {
|
|
265
|
-
|
|
266
|
+
AppUpdateStatus(
|
|
266
267
|
updateAvailable = false,
|
|
267
268
|
currentVersion = getCurrentAppVersion(),
|
|
268
269
|
availableVersion = null
|
|
@@ -25,6 +25,14 @@ class BackgroundNotificationManager(
|
|
|
25
25
|
private const val ACTION_UPDATE_NOW = "com.aoneahsan.nativeupdate.UPDATE_NOW"
|
|
26
26
|
private const val ACTION_UPDATE_LATER = "com.aoneahsan.nativeupdate.UPDATE_LATER"
|
|
27
27
|
private const val ACTION_DISMISS = "com.aoneahsan.nativeupdate.DISMISS"
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Static method to cancel notification from BroadcastReceiver
|
|
31
|
+
*/
|
|
32
|
+
fun cancelNotificationStatic(context: Context) {
|
|
33
|
+
val notificationManager = NotificationManagerCompat.from(context)
|
|
34
|
+
notificationManager.cancel(NOTIFICATION_ID)
|
|
35
|
+
}
|
|
28
36
|
}
|
|
29
37
|
|
|
30
38
|
private var preferences: NotificationPreferences = NotificationPreferences.default()
|
|
@@ -98,7 +106,7 @@ class BackgroundNotificationManager(
|
|
|
98
106
|
}
|
|
99
107
|
|
|
100
108
|
fun sendUpdateNotification(
|
|
101
|
-
appUpdate:
|
|
109
|
+
appUpdate: AppUpdateStatus?,
|
|
102
110
|
liveUpdate: LatestVersion?
|
|
103
111
|
): Boolean {
|
|
104
112
|
val permissionStatus = getPermissionStatus()
|
|
@@ -119,7 +127,7 @@ class BackgroundNotificationManager(
|
|
|
119
127
|
eventData.put("version", appUpdate?.availableVersion ?: liveUpdate?.version ?: "unknown")
|
|
120
128
|
eventData.put("action", "shown")
|
|
121
129
|
|
|
122
|
-
plugin.
|
|
130
|
+
plugin.notifyBackgroundUpdateListeners("backgroundUpdateNotification", eventData)
|
|
123
131
|
|
|
124
132
|
return true
|
|
125
133
|
} catch (e: Exception) {
|
|
@@ -133,8 +141,12 @@ class BackgroundNotificationManager(
|
|
|
133
141
|
notificationManager.cancel(NOTIFICATION_ID)
|
|
134
142
|
}
|
|
135
143
|
|
|
144
|
+
fun cancelUpdateNotification() {
|
|
145
|
+
cancelNotification()
|
|
146
|
+
}
|
|
147
|
+
|
|
136
148
|
private fun createNotificationBuilder(
|
|
137
|
-
appUpdate:
|
|
149
|
+
appUpdate: AppUpdateStatus?,
|
|
138
150
|
liveUpdate: LatestVersion?
|
|
139
151
|
): NotificationCompat.Builder {
|
|
140
152
|
val title = determineTitle(appUpdate, liveUpdate)
|
|
@@ -171,7 +183,7 @@ class BackgroundNotificationManager(
|
|
|
171
183
|
return builder
|
|
172
184
|
}
|
|
173
185
|
|
|
174
|
-
private fun determineTitle(appUpdate:
|
|
186
|
+
private fun determineTitle(appUpdate: AppUpdateStatus?, liveUpdate: LatestVersion?): String {
|
|
175
187
|
return when {
|
|
176
188
|
appUpdate?.updateAvailable == true && liveUpdate?.available == true -> "App Updates Available"
|
|
177
189
|
appUpdate?.updateAvailable == true -> "App Update Available"
|
|
@@ -180,7 +192,7 @@ class BackgroundNotificationManager(
|
|
|
180
192
|
}
|
|
181
193
|
}
|
|
182
194
|
|
|
183
|
-
private fun determineContent(appUpdate:
|
|
195
|
+
private fun determineContent(appUpdate: AppUpdateStatus?, liveUpdate: LatestVersion?): String {
|
|
184
196
|
return when {
|
|
185
197
|
appUpdate?.updateAvailable == true && liveUpdate?.available == true ->
|
|
186
198
|
"App version ${appUpdate.availableVersion} and content updates are available"
|
|
@@ -225,7 +237,7 @@ class BackgroundNotificationManager(
|
|
|
225
237
|
}
|
|
226
238
|
}
|
|
227
239
|
|
|
228
|
-
private fun createContentIntent(appUpdate:
|
|
240
|
+
private fun createContentIntent(appUpdate: AppUpdateStatus?, liveUpdate: LatestVersion?): PendingIntent {
|
|
229
241
|
val intent = context.packageManager.getLaunchIntentForPackage(context.packageName)
|
|
230
242
|
?: Intent()
|
|
231
243
|
|
|
@@ -242,7 +254,7 @@ class BackgroundNotificationManager(
|
|
|
242
254
|
|
|
243
255
|
private fun addActionButtons(
|
|
244
256
|
builder: NotificationCompat.Builder,
|
|
245
|
-
appUpdate:
|
|
257
|
+
appUpdate: AppUpdateStatus?,
|
|
246
258
|
liveUpdate: LatestVersion?
|
|
247
259
|
) {
|
|
248
260
|
val actionLabels = preferences.actionLabels ?: ActionLabels.default()
|
|
@@ -325,13 +337,13 @@ data class NotificationPreferences(
|
|
|
325
337
|
title = obj.getString("title"),
|
|
326
338
|
description = obj.getString("description"),
|
|
327
339
|
iconName = obj.getString("iconName"),
|
|
328
|
-
soundEnabled = obj.getBoolean("soundEnabled", true),
|
|
329
|
-
vibrationEnabled = obj.getBoolean("vibrationEnabled", true),
|
|
330
|
-
showActions = obj.getBoolean("showActions", true),
|
|
340
|
+
soundEnabled = obj.getBoolean("soundEnabled", true) ?: true,
|
|
341
|
+
vibrationEnabled = obj.getBoolean("vibrationEnabled", true) ?: true,
|
|
342
|
+
showActions = obj.getBoolean("showActions", true) ?: true,
|
|
331
343
|
actionLabels = actionLabelsObj?.let { ActionLabels.fromJSObject(it) } ?: ActionLabels.default(),
|
|
332
344
|
channelId = obj.getString("channelId"),
|
|
333
345
|
channelName = obj.getString("channelName"),
|
|
334
|
-
priority = NotificationPriority.fromString(priorityString)
|
|
346
|
+
priority = NotificationPriority.fromString(priorityString ?: "default")
|
|
335
347
|
)
|
|
336
348
|
}
|
|
337
349
|
}
|
|
@@ -33,6 +33,10 @@ class BackgroundUpdatePlugin : Plugin() {
|
|
|
33
33
|
BackgroundUpdateManager.registerBackgroundUpdatePlugin(this)
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
+
fun notifyBackgroundUpdateListeners(event: String, data: JSObject) {
|
|
37
|
+
notifyListeners(event, data)
|
|
38
|
+
}
|
|
39
|
+
|
|
36
40
|
@PluginMethod
|
|
37
41
|
fun enableBackgroundUpdates(call: PluginCall) {
|
|
38
42
|
try {
|
|
@@ -67,7 +71,7 @@ class BackgroundUpdatePlugin : Plugin() {
|
|
|
67
71
|
|
|
68
72
|
@PluginMethod
|
|
69
73
|
fun scheduleBackgroundCheck(call: PluginCall) {
|
|
70
|
-
val interval = call.getLong("interval"
|
|
74
|
+
val interval = call.getLong("interval") ?: (24 * 60 * 60 * 1000L) // Default 24 hours
|
|
71
75
|
scheduleBackgroundWork(interval)
|
|
72
76
|
call.resolve()
|
|
73
77
|
}
|
|
@@ -185,8 +189,8 @@ data class BackgroundUpdateConfig(
|
|
|
185
189
|
) {
|
|
186
190
|
companion object {
|
|
187
191
|
fun fromJSObject(obj: JSObject): BackgroundUpdateConfig {
|
|
188
|
-
val enabled = obj.getBoolean("enabled"
|
|
189
|
-
val checkInterval = obj.getInt("checkInterval"
|
|
192
|
+
val enabled = obj.getBoolean("enabled") ?: false
|
|
193
|
+
val checkInterval = obj.getInt("checkInterval") ?: (24 * 60 * 60 * 1000)
|
|
190
194
|
val updateTypesArray = obj.getJSONArray("updateTypes")
|
|
191
195
|
val updateTypes = mutableListOf<BackgroundUpdateType>()
|
|
192
196
|
|
|
@@ -201,14 +205,14 @@ data class BackgroundUpdateConfig(
|
|
|
201
205
|
enabled = enabled,
|
|
202
206
|
checkInterval = checkInterval,
|
|
203
207
|
updateTypes = updateTypes,
|
|
204
|
-
autoInstall = obj.getBoolean("autoInstall"
|
|
208
|
+
autoInstall = obj.getBoolean("autoInstall") ?: false,
|
|
205
209
|
notificationPreferences = notificationPrefs?.let { NotificationPreferences.fromJSObject(it) },
|
|
206
|
-
respectBatteryOptimization = obj.getBoolean("respectBatteryOptimization"
|
|
207
|
-
allowMeteredConnection = obj.getBoolean("allowMeteredConnection"
|
|
208
|
-
minimumBatteryLevel = obj.getInt("minimumBatteryLevel"
|
|
209
|
-
requireWifi = obj.getBoolean("requireWifi"
|
|
210
|
-
maxRetries = obj.getInt("maxRetries"
|
|
211
|
-
retryDelay = obj.getInt("retryDelay"
|
|
210
|
+
respectBatteryOptimization = obj.getBoolean("respectBatteryOptimization") ?: true,
|
|
211
|
+
allowMeteredConnection = obj.getBoolean("allowMeteredConnection") ?: false,
|
|
212
|
+
minimumBatteryLevel = obj.getInt("minimumBatteryLevel") ?: 20,
|
|
213
|
+
requireWifi = obj.getBoolean("requireWifi") ?: false,
|
|
214
|
+
maxRetries = obj.getInt("maxRetries") ?: 3,
|
|
215
|
+
retryDelay = obj.getInt("retryDelay") ?: 5000,
|
|
212
216
|
taskIdentifier = obj.getString("taskIdentifier")
|
|
213
217
|
)
|
|
214
218
|
}
|
|
@@ -274,7 +278,7 @@ data class BackgroundUpdateStatus(
|
|
|
274
278
|
data class BackgroundCheckResult(
|
|
275
279
|
val success: Boolean,
|
|
276
280
|
val updatesFound: Boolean,
|
|
277
|
-
val appUpdate:
|
|
281
|
+
val appUpdate: AppUpdateStatus? = null,
|
|
278
282
|
val liveUpdate: LatestVersion? = null,
|
|
279
283
|
val notificationSent: Boolean = false,
|
|
280
284
|
val error: UpdateError? = null
|
|
@@ -306,7 +310,7 @@ data class UpdateError(
|
|
|
306
310
|
}
|
|
307
311
|
|
|
308
312
|
// Placeholder data classes - would be defined in other plugins
|
|
309
|
-
data class
|
|
313
|
+
data class AppUpdateStatus(
|
|
310
314
|
val updateAvailable: Boolean,
|
|
311
315
|
val currentVersion: String,
|
|
312
316
|
val availableVersion: String? = null
|
|
@@ -65,7 +65,7 @@ class BackgroundUpdateWorker(
|
|
|
65
65
|
|
|
66
66
|
private suspend fun performBackgroundCheck(config: BackgroundUpdateConfig): BackgroundCheckResult {
|
|
67
67
|
try {
|
|
68
|
-
var appUpdate:
|
|
68
|
+
var appUpdate: AppUpdateStatus? = null
|
|
69
69
|
var liveUpdate: LatestVersion? = null
|
|
70
70
|
|
|
71
71
|
// Check for app updates
|
|
@@ -99,7 +99,7 @@ class BackgroundUpdateWorker(
|
|
|
99
99
|
}
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
-
private suspend fun checkForAppUpdate():
|
|
102
|
+
private suspend fun checkForAppUpdate(): AppUpdateStatus? {
|
|
103
103
|
return withContext(Dispatchers.IO) {
|
|
104
104
|
try {
|
|
105
105
|
val appUpdatePlugin = BackgroundUpdateManager.getAppUpdatePlugin()
|
|
@@ -111,7 +111,7 @@ class BackgroundUpdateWorker(
|
|
|
111
111
|
val currentVersion = getCurrentAppVersion()
|
|
112
112
|
val availableVersion = getAvailableAppVersion()
|
|
113
113
|
|
|
114
|
-
|
|
114
|
+
AppUpdateStatus(
|
|
115
115
|
updateAvailable = availableVersion != currentVersion,
|
|
116
116
|
currentVersion = currentVersion,
|
|
117
117
|
availableVersion = if (availableVersion != currentVersion) availableVersion else null
|
|
@@ -224,7 +224,7 @@ class BackgroundUpdateWorker(
|
|
|
224
224
|
progressData.put("status", if (result.success) "completed" else "failed")
|
|
225
225
|
progressData.put("percent", 100)
|
|
226
226
|
|
|
227
|
-
plugin?.
|
|
227
|
+
plugin?.notifyBackgroundUpdateListeners("backgroundUpdateProgress", progressData)
|
|
228
228
|
|
|
229
229
|
// Notify about notification if sent
|
|
230
230
|
if (result.notificationSent) {
|
|
@@ -233,7 +233,7 @@ class BackgroundUpdateWorker(
|
|
|
233
233
|
notificationData.put("updateAvailable", result.updatesFound)
|
|
234
234
|
notificationData.put("action", "shown")
|
|
235
235
|
|
|
236
|
-
plugin?.
|
|
236
|
+
plugin?.notifyBackgroundUpdateListeners("backgroundUpdateNotification", notificationData)
|
|
237
237
|
}
|
|
238
238
|
} catch (e: Exception) {
|
|
239
239
|
android.util.Log.e(TAG, "Failed to notify listeners", e)
|
|
@@ -77,9 +77,7 @@ class NativeUpdatePlugin : Plugin() {
|
|
|
77
77
|
appReviewPlugin.configure(it)
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
-
|
|
81
|
-
backgroundUpdatePlugin.configure(it)
|
|
82
|
-
}
|
|
80
|
+
// Background update configuration is handled separately via enableBackgroundUpdates
|
|
83
81
|
|
|
84
82
|
call.resolve()
|
|
85
83
|
} catch (e: Exception) {
|
|
@@ -259,7 +257,7 @@ class NativeUpdatePlugin : Plugin() {
|
|
|
259
257
|
}
|
|
260
258
|
}
|
|
261
259
|
|
|
262
|
-
|
|
260
|
+
override fun hasRequiredPermissions(): Boolean {
|
|
263
261
|
return hasPermission("storage")
|
|
264
262
|
}
|
|
265
263
|
}
|
|
@@ -38,8 +38,7 @@ class NotificationActionReceiver : BroadcastReceiver() {
|
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
// Cancel the notification
|
|
41
|
-
|
|
42
|
-
notificationManager.cancelUpdateNotification()
|
|
41
|
+
BackgroundNotificationManager.cancelNotificationStatic(context)
|
|
43
42
|
}
|
|
44
43
|
|
|
45
44
|
private fun handleInstallNow(context: Context, intent: Intent) {
|
package/cli/index.js
CHANGED
|
File without changes
|
|
@@ -214,12 +214,12 @@ class AppUpdatePlugin {
|
|
|
214
214
|
|
|
215
215
|
// MARK: - Data Models
|
|
216
216
|
|
|
217
|
-
struct AppUpdateInfo {
|
|
218
|
-
let updateAvailable: Bool
|
|
219
|
-
let currentVersion: String
|
|
220
|
-
let availableVersion: String?
|
|
217
|
+
public struct AppUpdateInfo {
|
|
218
|
+
public let updateAvailable: Bool
|
|
219
|
+
public let currentVersion: String
|
|
220
|
+
public let availableVersion: String?
|
|
221
221
|
|
|
222
|
-
func toDictionary() -> [String: Any] {
|
|
222
|
+
public func toDictionary() -> [String: Any] {
|
|
223
223
|
var obj: [String: Any] = [
|
|
224
224
|
"updateAvailable": updateAvailable,
|
|
225
225
|
"currentVersion": currentVersion
|
|
@@ -8,20 +8,17 @@ public class BackgroundUpdatePlugin: CAPPlugin {
|
|
|
8
8
|
|
|
9
9
|
private let backgroundTaskIdentifier = "com.aoneahsan.nativeupdate.background"
|
|
10
10
|
private var backgroundUpdateConfig: BackgroundUpdateConfig?
|
|
11
|
-
private var backgroundUpdateStatus
|
|
11
|
+
private var backgroundUpdateStatus = BackgroundUpdateStatus(
|
|
12
|
+
enabled: false,
|
|
13
|
+
isRunning: false,
|
|
14
|
+
checkCount: 0,
|
|
15
|
+
failureCount: 0
|
|
16
|
+
)
|
|
12
17
|
private var notificationManager: BackgroundNotificationManager?
|
|
13
18
|
|
|
14
19
|
public override func load() {
|
|
15
20
|
super.load()
|
|
16
21
|
|
|
17
|
-
// Initialize background update status
|
|
18
|
-
backgroundUpdateStatus = BackgroundUpdateStatus(
|
|
19
|
-
enabled: false,
|
|
20
|
-
isRunning: false,
|
|
21
|
-
checkCount: 0,
|
|
22
|
-
failureCount: 0
|
|
23
|
-
)
|
|
24
|
-
|
|
25
22
|
// Initialize notification manager
|
|
26
23
|
notificationManager = BackgroundNotificationManager(plugin: self)
|
|
27
24
|
|
|
@@ -33,6 +30,11 @@ public class BackgroundUpdatePlugin: CAPPlugin {
|
|
|
33
30
|
}
|
|
34
31
|
}
|
|
35
32
|
|
|
33
|
+
func configure(_ config: [String: Any]) throws {
|
|
34
|
+
// Configuration is handled in enableBackgroundUpdates
|
|
35
|
+
// This method exists for consistency with other plugins
|
|
36
|
+
}
|
|
37
|
+
|
|
36
38
|
@objc func enableBackgroundUpdates(_ call: CAPPluginCall) {
|
|
37
39
|
guard let configData = call.options else {
|
|
38
40
|
call.reject("Missing configuration")
|
|
@@ -40,7 +42,13 @@ public class BackgroundUpdatePlugin: CAPPlugin {
|
|
|
40
42
|
}
|
|
41
43
|
|
|
42
44
|
do {
|
|
43
|
-
|
|
45
|
+
// Convert [AnyHashable: Any] to [String: Any]
|
|
46
|
+
let stringKeyedConfig = configData.reduce(into: [String: Any]()) { result, pair in
|
|
47
|
+
if let key = pair.key as? String {
|
|
48
|
+
result[key] = pair.value
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
let config = try BackgroundUpdateConfig.from(stringKeyedConfig)
|
|
44
52
|
backgroundUpdateConfig = config
|
|
45
53
|
backgroundUpdateStatus.enabled = config.enabled
|
|
46
54
|
|
|
@@ -88,7 +96,14 @@ public class BackgroundUpdatePlugin: CAPPlugin {
|
|
|
88
96
|
return
|
|
89
97
|
}
|
|
90
98
|
|
|
91
|
-
|
|
99
|
+
// Convert [AnyHashable: Any] to [String: Any]
|
|
100
|
+
let stringKeyedPreferences = preferences.reduce(into: [String: Any]()) { result, pair in
|
|
101
|
+
if let key = pair.key as? String {
|
|
102
|
+
result[key] = pair.value
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
notificationManager?.setPreferences(stringKeyedPreferences)
|
|
92
107
|
call.resolve()
|
|
93
108
|
}
|
|
94
109
|
|
|
@@ -172,6 +187,8 @@ public class BackgroundUpdatePlugin: CAPPlugin {
|
|
|
172
187
|
return BackgroundCheckResult(
|
|
173
188
|
success: false,
|
|
174
189
|
updatesFound: false,
|
|
190
|
+
appUpdate: nil,
|
|
191
|
+
liveUpdate: nil,
|
|
175
192
|
notificationSent: false,
|
|
176
193
|
error: UpdateError(code: "INVALID_CONFIG", message: "Background updates not enabled")
|
|
177
194
|
)
|
|
@@ -214,7 +231,8 @@ public class BackgroundUpdatePlugin: CAPPlugin {
|
|
|
214
231
|
updatesFound: updatesFound,
|
|
215
232
|
appUpdate: appUpdate,
|
|
216
233
|
liveUpdate: liveUpdate,
|
|
217
|
-
notificationSent: notificationSent
|
|
234
|
+
notificationSent: notificationSent,
|
|
235
|
+
error: nil
|
|
218
236
|
)
|
|
219
237
|
|
|
220
238
|
} catch {
|
|
@@ -230,6 +248,8 @@ public class BackgroundUpdatePlugin: CAPPlugin {
|
|
|
230
248
|
return BackgroundCheckResult(
|
|
231
249
|
success: false,
|
|
232
250
|
updatesFound: false,
|
|
251
|
+
appUpdate: nil,
|
|
252
|
+
liveUpdate: nil,
|
|
233
253
|
notificationSent: false,
|
|
234
254
|
error: updateError
|
|
235
255
|
)
|
|
@@ -7,7 +7,7 @@ class LiveUpdatePlugin {
|
|
|
7
7
|
private var config: [String: Any]?
|
|
8
8
|
private var progressListener: (([String: Any]) -> Void)?
|
|
9
9
|
private var stateChangeListener: (([String: Any]) -> Void)?
|
|
10
|
-
private var session: URLSession
|
|
10
|
+
private var session: URLSession!
|
|
11
11
|
private var downloadTask: URLSessionDownloadTask?
|
|
12
12
|
private let securityManager = SecurityManager()
|
|
13
13
|
|
|
@@ -444,10 +444,15 @@ class LiveUpdatePlugin {
|
|
|
444
444
|
}
|
|
445
445
|
|
|
446
446
|
private func getCurrentVersion() -> String {
|
|
447
|
-
if
|
|
448
|
-
|
|
447
|
+
// First check if we have an active bundle with version
|
|
448
|
+
let defaults = UserDefaults.standard
|
|
449
|
+
if let activeBundleId = defaults.string(forKey: "native_update_active_bundle"),
|
|
450
|
+
let bundles = defaults.dictionary(forKey: "native_update_bundles"),
|
|
451
|
+
let bundleInfo = bundles[activeBundleId] as? [String: Any],
|
|
452
|
+
let version = bundleInfo["version"] as? String {
|
|
449
453
|
return version
|
|
450
454
|
}
|
|
455
|
+
// Fall back to app version
|
|
451
456
|
return Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "1.0.0"
|
|
452
457
|
}
|
|
453
458
|
|
|
@@ -484,7 +489,7 @@ class LiveUpdatePlugin {
|
|
|
484
489
|
// Return default bundle
|
|
485
490
|
return [
|
|
486
491
|
"bundleId": "default",
|
|
487
|
-
"version":
|
|
492
|
+
"version": Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "1.0.0",
|
|
488
493
|
"path": "/",
|
|
489
494
|
"downloadTime": Date().timeIntervalSince1970 * 1000,
|
|
490
495
|
"size": 0,
|
|
@@ -555,19 +560,14 @@ class LiveUpdatePlugin {
|
|
|
555
560
|
// Create destination directory
|
|
556
561
|
try FileManager.default.createDirectory(at: destinationUrl, withIntermediateDirectories: true)
|
|
557
562
|
|
|
558
|
-
// Use
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
process.arguments = ["-o", zipUrl.path, "-d", destinationUrl.path]
|
|
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
|
|
562
566
|
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
throw NSError(domain: "LiveUpdatePlugin", code: 5, userInfo: [
|
|
568
|
-
NSLocalizedDescriptionKey: "Failed to extract bundle"
|
|
569
|
-
])
|
|
570
|
-
}
|
|
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
|
+
])
|
|
571
571
|
}
|
|
572
572
|
|
|
573
573
|
private func configureWebViewPath(_ path: String) {
|
|
@@ -581,11 +581,11 @@ class LiveUpdatePlugin {
|
|
|
581
581
|
|
|
582
582
|
// MARK: - Data Models
|
|
583
583
|
|
|
584
|
-
struct LatestVersion {
|
|
585
|
-
let available: Bool
|
|
586
|
-
let version: String?
|
|
584
|
+
public struct LatestVersion {
|
|
585
|
+
public let available: Bool
|
|
586
|
+
public let version: String?
|
|
587
587
|
|
|
588
|
-
func toDictionary() -> [String: Any] {
|
|
588
|
+
public func toDictionary() -> [String: Any] {
|
|
589
589
|
var obj: [String: Any] = [
|
|
590
590
|
"available": available
|
|
591
591
|
]
|
|
@@ -646,8 +646,8 @@ class CertificatePinningDelegate: NSObject, URLSessionDelegate {
|
|
|
646
646
|
|
|
647
647
|
private func getCertificatePins(for host: String) -> [String] {
|
|
648
648
|
// Get pins from security manager configuration
|
|
649
|
-
|
|
650
|
-
|
|
649
|
+
let securityInfo = securityManager.getSecurityInfo()
|
|
650
|
+
guard let certificatePinning = securityInfo["certificatePinning"] as? [String: Any],
|
|
651
651
|
certificatePinning["enabled"] as? Bool == true,
|
|
652
652
|
let hostPins = certificatePinning["pins"] as? [String: [String]] else {
|
|
653
653
|
return []
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "native-update",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.2",
|
|
4
4
|
"description": "Foundation package for building a comprehensive update system for Capacitor apps. Provides architecture and interfaces but requires backend implementation.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/plugin.cjs.js",
|