native-update 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CapacitorNativeUpdate.podspec +18 -0
- package/LICENSE +21 -0
- package/Readme.md +451 -0
- package/android/build.gradle +92 -0
- package/android/gradle/wrapper/gradle-wrapper.properties +8 -0
- package/android/gradle.properties +17 -0
- package/android/proguard-rules.pro +29 -0
- package/android/settings.gradle +2 -0
- package/android/src/main/AndroidManifest.xml +34 -0
- package/android/src/main/java/com/aoneahsan/nativeupdate/AppReviewPlugin.kt +153 -0
- package/android/src/main/java/com/aoneahsan/nativeupdate/AppUpdatePlugin.kt +275 -0
- package/android/src/main/java/com/aoneahsan/nativeupdate/BackgroundNotificationManager.kt +390 -0
- package/android/src/main/java/com/aoneahsan/nativeupdate/BackgroundUpdateManager.kt +46 -0
- package/android/src/main/java/com/aoneahsan/nativeupdate/BackgroundUpdatePlugin.kt +333 -0
- package/android/src/main/java/com/aoneahsan/nativeupdate/BackgroundUpdateWorker.kt +251 -0
- package/android/src/main/java/com/aoneahsan/nativeupdate/CapacitorNativeUpdatePlugin.kt +265 -0
- package/android/src/main/java/com/aoneahsan/nativeupdate/LiveUpdatePlugin.kt +526 -0
- package/android/src/main/java/com/aoneahsan/nativeupdate/NotificationActionReceiver.kt +99 -0
- package/android/src/main/java/com/aoneahsan/nativeupdate/SecurityManager.kt +249 -0
- package/dist/esm/__tests__/bundle-manager.test.d.ts +1 -0
- package/dist/esm/__tests__/bundle-manager.test.js +123 -0
- package/dist/esm/__tests__/bundle-manager.test.js.map +1 -0
- package/dist/esm/__tests__/config.test.d.ts +1 -0
- package/dist/esm/__tests__/config.test.js +69 -0
- package/dist/esm/__tests__/config.test.js.map +1 -0
- package/dist/esm/__tests__/integration.test.d.ts +1 -0
- package/dist/esm/__tests__/integration.test.js +78 -0
- package/dist/esm/__tests__/integration.test.js.map +1 -0
- package/dist/esm/__tests__/security.test.d.ts +1 -0
- package/dist/esm/__tests__/security.test.js +54 -0
- package/dist/esm/__tests__/security.test.js.map +1 -0
- package/dist/esm/__tests__/version-manager.test.d.ts +1 -0
- package/dist/esm/__tests__/version-manager.test.js +45 -0
- package/dist/esm/__tests__/version-manager.test.js.map +1 -0
- package/dist/esm/app-review/app-review-manager.d.ts +24 -0
- package/dist/esm/app-review/app-review-manager.js +195 -0
- package/dist/esm/app-review/app-review-manager.js.map +1 -0
- package/dist/esm/app-review/index.d.ts +5 -0
- package/dist/esm/app-review/index.js +6 -0
- package/dist/esm/app-review/index.js.map +1 -0
- package/dist/esm/app-review/platform-review-handler.d.ts +20 -0
- package/dist/esm/app-review/platform-review-handler.js +138 -0
- package/dist/esm/app-review/platform-review-handler.js.map +1 -0
- package/dist/esm/app-review/review-conditions-checker.d.ts +22 -0
- package/dist/esm/app-review/review-conditions-checker.js +155 -0
- package/dist/esm/app-review/review-conditions-checker.js.map +1 -0
- package/dist/esm/app-review/review-rate-limiter.d.ts +23 -0
- package/dist/esm/app-review/review-rate-limiter.js +164 -0
- package/dist/esm/app-review/review-rate-limiter.js.map +1 -0
- package/dist/esm/app-review/types.d.ts +41 -0
- package/dist/esm/app-review/types.js +2 -0
- package/dist/esm/app-review/types.js.map +1 -0
- package/dist/esm/app-update/app-update-checker.d.ts +13 -0
- package/dist/esm/app-update/app-update-checker.js +104 -0
- package/dist/esm/app-update/app-update-checker.js.map +1 -0
- package/dist/esm/app-update/app-update-installer.d.ts +19 -0
- package/dist/esm/app-update/app-update-installer.js +123 -0
- package/dist/esm/app-update/app-update-installer.js.map +1 -0
- package/dist/esm/app-update/app-update-manager.d.ts +28 -0
- package/dist/esm/app-update/app-update-manager.js +199 -0
- package/dist/esm/app-update/app-update-manager.js.map +1 -0
- package/dist/esm/app-update/app-update-notifier.d.ts +14 -0
- package/dist/esm/app-update/app-update-notifier.js +100 -0
- package/dist/esm/app-update/app-update-notifier.js.map +1 -0
- package/dist/esm/app-update/index.d.ts +6 -0
- package/dist/esm/app-update/index.js +7 -0
- package/dist/esm/app-update/index.js.map +1 -0
- package/dist/esm/app-update/platform-app-update.d.ts +19 -0
- package/dist/esm/app-update/platform-app-update.js +129 -0
- package/dist/esm/app-update/platform-app-update.js.map +1 -0
- package/dist/esm/app-update/types.d.ts +58 -0
- package/dist/esm/app-update/types.js +12 -0
- package/dist/esm/app-update/types.js.map +1 -0
- package/dist/esm/background-update/background-scheduler.d.ts +17 -0
- package/dist/esm/background-update/background-scheduler.js +195 -0
- package/dist/esm/background-update/background-scheduler.js.map +1 -0
- package/dist/esm/background-update/index.d.ts +3 -0
- package/dist/esm/background-update/index.js +3 -0
- package/dist/esm/background-update/index.js.map +1 -0
- package/dist/esm/background-update/notification-manager.d.ts +29 -0
- package/dist/esm/background-update/notification-manager.js +89 -0
- package/dist/esm/background-update/notification-manager.js.map +1 -0
- package/dist/esm/core/analytics.d.ts +70 -0
- package/dist/esm/core/analytics.js +137 -0
- package/dist/esm/core/analytics.js.map +1 -0
- package/dist/esm/core/cache-manager.d.ts +72 -0
- package/dist/esm/core/cache-manager.js +275 -0
- package/dist/esm/core/cache-manager.js.map +1 -0
- package/dist/esm/core/config.d.ts +48 -0
- package/dist/esm/core/config.js +83 -0
- package/dist/esm/core/config.js.map +1 -0
- package/dist/esm/core/errors.d.ts +51 -0
- package/dist/esm/core/errors.js +80 -0
- package/dist/esm/core/errors.js.map +1 -0
- package/dist/esm/core/logger.d.ts +21 -0
- package/dist/esm/core/logger.js +109 -0
- package/dist/esm/core/logger.js.map +1 -0
- package/dist/esm/core/performance.d.ts +53 -0
- package/dist/esm/core/performance.js +140 -0
- package/dist/esm/core/performance.js.map +1 -0
- package/dist/esm/core/plugin-manager.d.ts +66 -0
- package/dist/esm/core/plugin-manager.js +148 -0
- package/dist/esm/core/plugin-manager.js.map +1 -0
- package/dist/esm/core/security.d.ts +93 -0
- package/dist/esm/core/security.js +315 -0
- package/dist/esm/core/security.js.map +1 -0
- package/dist/esm/definitions.d.ts +639 -0
- package/dist/esm/definitions.js +103 -0
- package/dist/esm/definitions.js.map +1 -0
- package/dist/esm/index.d.ts +12 -0
- package/dist/esm/index.js +16 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/live-update/bundle-manager.d.ts +94 -0
- package/dist/esm/live-update/bundle-manager.js +310 -0
- package/dist/esm/live-update/bundle-manager.js.map +1 -0
- package/dist/esm/live-update/certificate-pinning.d.ts +38 -0
- package/dist/esm/live-update/certificate-pinning.js +78 -0
- package/dist/esm/live-update/certificate-pinning.js.map +1 -0
- package/dist/esm/live-update/download-manager.d.ts +67 -0
- package/dist/esm/live-update/download-manager.js +319 -0
- package/dist/esm/live-update/download-manager.js.map +1 -0
- package/dist/esm/live-update/update-manager.d.ts +52 -0
- package/dist/esm/live-update/update-manager.js +294 -0
- package/dist/esm/live-update/update-manager.js.map +1 -0
- package/dist/esm/live-update/version-manager.d.ts +84 -0
- package/dist/esm/live-update/version-manager.js +335 -0
- package/dist/esm/live-update/version-manager.js.map +1 -0
- package/dist/esm/plugin.d.ts +6 -0
- package/dist/esm/plugin.js +283 -0
- package/dist/esm/plugin.js.map +1 -0
- package/dist/esm/security/crypto.d.ts +25 -0
- package/dist/esm/security/crypto.js +70 -0
- package/dist/esm/security/crypto.js.map +1 -0
- package/dist/esm/security/validator.d.ts +60 -0
- package/dist/esm/security/validator.js +143 -0
- package/dist/esm/security/validator.js.map +1 -0
- package/dist/esm/web.d.ts +74 -0
- package/dist/esm/web.js +595 -0
- package/dist/esm/web.js.map +1 -0
- package/dist/plugin.cjs.js +2 -0
- package/dist/plugin.cjs.js.map +1 -0
- package/dist/plugin.esm.js +2 -0
- package/dist/plugin.esm.js.map +1 -0
- package/dist/plugin.js +3 -0
- package/dist/plugin.js.map +1 -0
- package/docs/APP_REVIEW_GUIDE.md +768 -0
- package/docs/BUNDLE_SIGNING.md +264 -0
- package/docs/LIVE_UPDATES_GUIDE.md +650 -0
- package/docs/MIGRATION.md +192 -0
- package/docs/NATIVE_UPDATES_GUIDE.md +694 -0
- package/docs/QUICK_START.md +606 -0
- package/docs/README.md +111 -0
- package/docs/REMAINING_FEATURES.md +139 -0
- package/docs/api/app-review-api.md +259 -0
- package/docs/api/app-update-api.md +238 -0
- package/docs/api/events-api.md +451 -0
- package/docs/api/live-update-api.md +265 -0
- package/docs/background-updates.md +392 -0
- package/docs/examples/advanced-scenarios.md +410 -0
- package/docs/examples/basic-usage.md +185 -0
- package/docs/features/app-reviews.md +975 -0
- package/docs/features/app-updates.md +785 -0
- package/docs/features/live-updates.md +633 -0
- package/docs/getting-started/configuration.md +468 -0
- package/docs/getting-started/installation.md +209 -0
- package/docs/getting-started/quick-start.md +379 -0
- package/docs/guides/deployment-guide.md +333 -0
- package/docs/guides/migration-from-codepush.md +142 -0
- package/docs/guides/security-best-practices.md +1057 -0
- package/docs/guides/testing-guide.md +373 -0
- package/docs/production-readiness.md +478 -0
- package/docs/security/certificate-pinning.md +122 -0
- package/docs/server-requirements.md +147 -0
- package/ios/Plugin/AppReview/AppReviewPlugin.swift +158 -0
- package/ios/Plugin/AppUpdate/AppUpdatePlugin.swift +234 -0
- package/ios/Plugin/BackgroundUpdate/BackgroundNotificationManager.swift +329 -0
- package/ios/Plugin/BackgroundUpdate/BackgroundUpdatePlugin.swift +396 -0
- package/ios/Plugin/CapacitorNativeUpdatePlugin.m +45 -0
- package/ios/Plugin/CapacitorNativeUpdatePlugin.swift +190 -0
- package/ios/Plugin/Info.plist +43 -0
- package/ios/Plugin/LiveUpdate/LiveUpdatePlugin.swift +689 -0
- package/ios/Plugin/LiveUpdate/WebViewConfiguration.swift +45 -0
- package/ios/Plugin/Security/SecurityManager.swift +289 -0
- package/package.json +90 -0
|
@@ -0,0 +1,390 @@
|
|
|
1
|
+
package com.aoneahsan.nativeupdate
|
|
2
|
+
|
|
3
|
+
import android.app.NotificationChannel
|
|
4
|
+
import android.app.NotificationManager
|
|
5
|
+
import android.app.PendingIntent
|
|
6
|
+
import android.content.Context
|
|
7
|
+
import android.content.Intent
|
|
8
|
+
import android.content.pm.PackageManager
|
|
9
|
+
import android.os.Build
|
|
10
|
+
import androidx.core.app.NotificationCompat
|
|
11
|
+
import androidx.core.app.NotificationManagerCompat
|
|
12
|
+
import androidx.core.content.ContextCompat
|
|
13
|
+
import com.getcapacitor.JSObject
|
|
14
|
+
import com.getcapacitor.Plugin
|
|
15
|
+
|
|
16
|
+
class BackgroundNotificationManager(
|
|
17
|
+
private val context: Context,
|
|
18
|
+
private val plugin: BackgroundUpdatePlugin
|
|
19
|
+
) {
|
|
20
|
+
|
|
21
|
+
companion object {
|
|
22
|
+
private const val CHANNEL_ID = "capacitor_native_update"
|
|
23
|
+
private const val CHANNEL_NAME = "App Updates"
|
|
24
|
+
private const val NOTIFICATION_ID = 1001
|
|
25
|
+
private const val ACTION_UPDATE_NOW = "com.aoneahsan.nativeupdate.UPDATE_NOW"
|
|
26
|
+
private const val ACTION_UPDATE_LATER = "com.aoneahsan.nativeupdate.UPDATE_LATER"
|
|
27
|
+
private const val ACTION_DISMISS = "com.aoneahsan.nativeupdate.DISMISS"
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
private var preferences: NotificationPreferences = NotificationPreferences.default()
|
|
31
|
+
|
|
32
|
+
fun createNotificationChannel() {
|
|
33
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
34
|
+
val channel = NotificationChannel(
|
|
35
|
+
CHANNEL_ID,
|
|
36
|
+
CHANNEL_NAME,
|
|
37
|
+
NotificationManager.IMPORTANCE_DEFAULT
|
|
38
|
+
).apply {
|
|
39
|
+
description = "Notifications for app updates"
|
|
40
|
+
enableLights(true)
|
|
41
|
+
enableVibration(true)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
|
45
|
+
notificationManager.createNotificationChannel(channel)
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
fun setPreferences(preferencesData: JSObject) {
|
|
50
|
+
preferences = NotificationPreferences.fromJSObject(preferencesData)
|
|
51
|
+
|
|
52
|
+
// Update channel if preferences changed
|
|
53
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
54
|
+
val channelId = preferences.channelId ?: CHANNEL_ID
|
|
55
|
+
val channelName = preferences.channelName ?: CHANNEL_NAME
|
|
56
|
+
|
|
57
|
+
val channel = NotificationChannel(
|
|
58
|
+
channelId,
|
|
59
|
+
channelName,
|
|
60
|
+
getNotificationImportance(preferences.priority)
|
|
61
|
+
).apply {
|
|
62
|
+
description = "Notifications for app updates"
|
|
63
|
+
enableLights(true)
|
|
64
|
+
enableVibration(preferences.vibrationEnabled)
|
|
65
|
+
|
|
66
|
+
if (!preferences.soundEnabled) {
|
|
67
|
+
setSound(null, null)
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
|
72
|
+
notificationManager.createNotificationChannel(channel)
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
fun getPermissionStatus(): NotificationPermissionStatus {
|
|
77
|
+
val notificationManager = NotificationManagerCompat.from(context)
|
|
78
|
+
val areNotificationsEnabled = notificationManager.areNotificationsEnabled()
|
|
79
|
+
|
|
80
|
+
return NotificationPermissionStatus(
|
|
81
|
+
granted = areNotificationsEnabled,
|
|
82
|
+
canRequest = !areNotificationsEnabled,
|
|
83
|
+
shouldShowRationale = false // Android doesn't have this concept
|
|
84
|
+
)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
fun requestPermissions(): Boolean {
|
|
88
|
+
// On Android 13+, notification permissions need to be requested
|
|
89
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
|
90
|
+
return ContextCompat.checkSelfPermission(
|
|
91
|
+
context,
|
|
92
|
+
android.Manifest.permission.POST_NOTIFICATIONS
|
|
93
|
+
) == PackageManager.PERMISSION_GRANTED
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// For older versions, notifications are enabled by default
|
|
97
|
+
return true
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
fun sendUpdateNotification(
|
|
101
|
+
appUpdate: AppUpdateInfo?,
|
|
102
|
+
liveUpdate: LatestVersion?
|
|
103
|
+
): Boolean {
|
|
104
|
+
val permissionStatus = getPermissionStatus()
|
|
105
|
+
if (!permissionStatus.granted) {
|
|
106
|
+
return false
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
val notificationBuilder = createNotificationBuilder(appUpdate, liveUpdate)
|
|
110
|
+
|
|
111
|
+
try {
|
|
112
|
+
val notificationManager = NotificationManagerCompat.from(context)
|
|
113
|
+
notificationManager.notify(NOTIFICATION_ID, notificationBuilder.build())
|
|
114
|
+
|
|
115
|
+
// Notify listeners
|
|
116
|
+
val eventData = JSObject()
|
|
117
|
+
eventData.put("type", if (appUpdate?.updateAvailable == true) "app_update" else "live_update")
|
|
118
|
+
eventData.put("updateAvailable", true)
|
|
119
|
+
eventData.put("version", appUpdate?.availableVersion ?: liveUpdate?.version ?: "unknown")
|
|
120
|
+
eventData.put("action", "shown")
|
|
121
|
+
|
|
122
|
+
plugin.notifyListeners("backgroundUpdateNotification", eventData)
|
|
123
|
+
|
|
124
|
+
return true
|
|
125
|
+
} catch (e: Exception) {
|
|
126
|
+
android.util.Log.e("BackgroundNotificationManager", "Failed to send notification", e)
|
|
127
|
+
return false
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
fun cancelNotification() {
|
|
132
|
+
val notificationManager = NotificationManagerCompat.from(context)
|
|
133
|
+
notificationManager.cancel(NOTIFICATION_ID)
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
private fun createNotificationBuilder(
|
|
137
|
+
appUpdate: AppUpdateInfo?,
|
|
138
|
+
liveUpdate: LatestVersion?
|
|
139
|
+
): NotificationCompat.Builder {
|
|
140
|
+
val title = determineTitle(appUpdate, liveUpdate)
|
|
141
|
+
val content = determineContent(appUpdate, liveUpdate)
|
|
142
|
+
|
|
143
|
+
val builder = NotificationCompat.Builder(context, preferences.channelId ?: CHANNEL_ID)
|
|
144
|
+
.setSmallIcon(getNotificationIcon())
|
|
145
|
+
.setContentTitle(title)
|
|
146
|
+
.setContentText(content)
|
|
147
|
+
.setStyle(NotificationCompat.BigTextStyle().bigText(content))
|
|
148
|
+
.setPriority(getNotificationPriority(preferences.priority))
|
|
149
|
+
.setAutoCancel(true)
|
|
150
|
+
.setOnlyAlertOnce(true)
|
|
151
|
+
|
|
152
|
+
// Set sound
|
|
153
|
+
if (preferences.soundEnabled) {
|
|
154
|
+
builder.setDefaults(NotificationCompat.DEFAULT_SOUND)
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Set vibration
|
|
158
|
+
if (preferences.vibrationEnabled) {
|
|
159
|
+
builder.setVibrate(longArrayOf(0, 300, 300, 300))
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Set content intent (tap action)
|
|
163
|
+
val contentIntent = createContentIntent(appUpdate, liveUpdate)
|
|
164
|
+
builder.setContentIntent(contentIntent)
|
|
165
|
+
|
|
166
|
+
// Add action buttons if enabled
|
|
167
|
+
if (preferences.showActions) {
|
|
168
|
+
addActionButtons(builder, appUpdate, liveUpdate)
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return builder
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
private fun determineTitle(appUpdate: AppUpdateInfo?, liveUpdate: LatestVersion?): String {
|
|
175
|
+
return when {
|
|
176
|
+
appUpdate?.updateAvailable == true && liveUpdate?.available == true -> "App Updates Available"
|
|
177
|
+
appUpdate?.updateAvailable == true -> "App Update Available"
|
|
178
|
+
liveUpdate?.available == true -> "Content Update Available"
|
|
179
|
+
else -> preferences.title ?: "App Update Available"
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
private fun determineContent(appUpdate: AppUpdateInfo?, liveUpdate: LatestVersion?): String {
|
|
184
|
+
return when {
|
|
185
|
+
appUpdate?.updateAvailable == true && liveUpdate?.available == true ->
|
|
186
|
+
"App version ${appUpdate.availableVersion} and content updates are available"
|
|
187
|
+
appUpdate?.updateAvailable == true ->
|
|
188
|
+
"Version ${appUpdate.availableVersion} is available"
|
|
189
|
+
liveUpdate?.available == true ->
|
|
190
|
+
"New content version ${liveUpdate.version} is available"
|
|
191
|
+
else -> preferences.description ?: "A new version of the app is available"
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
private fun getNotificationIcon(): Int {
|
|
196
|
+
// Try to get custom icon, fallback to default
|
|
197
|
+
return try {
|
|
198
|
+
context.packageManager.getApplicationInfo(context.packageName, 0).icon
|
|
199
|
+
} catch (e: Exception) {
|
|
200
|
+
android.R.drawable.ic_dialog_info
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
private fun getNotificationPriority(priority: NotificationPriority): Int {
|
|
205
|
+
return when (priority) {
|
|
206
|
+
NotificationPriority.MIN -> NotificationCompat.PRIORITY_MIN
|
|
207
|
+
NotificationPriority.LOW -> NotificationCompat.PRIORITY_LOW
|
|
208
|
+
NotificationPriority.DEFAULT -> NotificationCompat.PRIORITY_DEFAULT
|
|
209
|
+
NotificationPriority.HIGH -> NotificationCompat.PRIORITY_HIGH
|
|
210
|
+
NotificationPriority.MAX -> NotificationCompat.PRIORITY_MAX
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
private fun getNotificationImportance(priority: NotificationPriority): Int {
|
|
215
|
+
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
216
|
+
when (priority) {
|
|
217
|
+
NotificationPriority.MIN -> NotificationManager.IMPORTANCE_MIN
|
|
218
|
+
NotificationPriority.LOW -> NotificationManager.IMPORTANCE_LOW
|
|
219
|
+
NotificationPriority.DEFAULT -> NotificationManager.IMPORTANCE_DEFAULT
|
|
220
|
+
NotificationPriority.HIGH -> NotificationManager.IMPORTANCE_HIGH
|
|
221
|
+
NotificationPriority.MAX -> NotificationManager.IMPORTANCE_MAX
|
|
222
|
+
}
|
|
223
|
+
} else {
|
|
224
|
+
NotificationManager.IMPORTANCE_DEFAULT
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
private fun createContentIntent(appUpdate: AppUpdateInfo?, liveUpdate: LatestVersion?): PendingIntent {
|
|
229
|
+
val intent = context.packageManager.getLaunchIntentForPackage(context.packageName)
|
|
230
|
+
?: Intent()
|
|
231
|
+
|
|
232
|
+
intent.putExtra("notification_action", "tapped")
|
|
233
|
+
intent.putExtra("update_type", if (appUpdate?.updateAvailable == true) "app_update" else "live_update")
|
|
234
|
+
|
|
235
|
+
return PendingIntent.getActivity(
|
|
236
|
+
context,
|
|
237
|
+
0,
|
|
238
|
+
intent,
|
|
239
|
+
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
|
|
240
|
+
)
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
private fun addActionButtons(
|
|
244
|
+
builder: NotificationCompat.Builder,
|
|
245
|
+
appUpdate: AppUpdateInfo?,
|
|
246
|
+
liveUpdate: LatestVersion?
|
|
247
|
+
) {
|
|
248
|
+
val actionLabels = preferences.actionLabels ?: ActionLabels.default()
|
|
249
|
+
|
|
250
|
+
// Update Now action
|
|
251
|
+
val updateNowIntent = Intent(ACTION_UPDATE_NOW).apply {
|
|
252
|
+
putExtra("update_type", if (appUpdate?.updateAvailable == true) "app_update" else "live_update")
|
|
253
|
+
}
|
|
254
|
+
val updateNowPendingIntent = PendingIntent.getBroadcast(
|
|
255
|
+
context,
|
|
256
|
+
1,
|
|
257
|
+
updateNowIntent,
|
|
258
|
+
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
|
|
259
|
+
)
|
|
260
|
+
|
|
261
|
+
builder.addAction(
|
|
262
|
+
android.R.drawable.ic_menu_upload,
|
|
263
|
+
actionLabels.updateNow ?: "Update Now",
|
|
264
|
+
updateNowPendingIntent
|
|
265
|
+
)
|
|
266
|
+
|
|
267
|
+
// Update Later action
|
|
268
|
+
val updateLaterIntent = Intent(ACTION_UPDATE_LATER)
|
|
269
|
+
val updateLaterPendingIntent = PendingIntent.getBroadcast(
|
|
270
|
+
context,
|
|
271
|
+
2,
|
|
272
|
+
updateLaterIntent,
|
|
273
|
+
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
|
|
274
|
+
)
|
|
275
|
+
|
|
276
|
+
builder.addAction(
|
|
277
|
+
android.R.drawable.ic_menu_recent_history,
|
|
278
|
+
actionLabels.updateLater ?: "Later",
|
|
279
|
+
updateLaterPendingIntent
|
|
280
|
+
)
|
|
281
|
+
|
|
282
|
+
// Dismiss action
|
|
283
|
+
val dismissIntent = Intent(ACTION_DISMISS)
|
|
284
|
+
val dismissPendingIntent = PendingIntent.getBroadcast(
|
|
285
|
+
context,
|
|
286
|
+
3,
|
|
287
|
+
dismissIntent,
|
|
288
|
+
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
|
|
289
|
+
)
|
|
290
|
+
|
|
291
|
+
builder.addAction(
|
|
292
|
+
android.R.drawable.ic_menu_close_clear_cancel,
|
|
293
|
+
actionLabels.dismiss ?: "Dismiss",
|
|
294
|
+
dismissPendingIntent
|
|
295
|
+
)
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
data class NotificationPreferences(
|
|
300
|
+
val title: String? = null,
|
|
301
|
+
val description: String? = null,
|
|
302
|
+
val iconName: String? = null,
|
|
303
|
+
val soundEnabled: Boolean = true,
|
|
304
|
+
val vibrationEnabled: Boolean = true,
|
|
305
|
+
val showActions: Boolean = true,
|
|
306
|
+
val actionLabels: ActionLabels? = null,
|
|
307
|
+
val channelId: String? = null,
|
|
308
|
+
val channelName: String? = null,
|
|
309
|
+
val priority: NotificationPriority = NotificationPriority.DEFAULT
|
|
310
|
+
) {
|
|
311
|
+
companion object {
|
|
312
|
+
fun default(): NotificationPreferences {
|
|
313
|
+
return NotificationPreferences(
|
|
314
|
+
title = "App Update Available",
|
|
315
|
+
description = "A new version of the app is available",
|
|
316
|
+
actionLabels = ActionLabels.default()
|
|
317
|
+
)
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
fun fromJSObject(obj: JSObject): NotificationPreferences {
|
|
321
|
+
val actionLabelsObj = obj.getJSObject("actionLabels")
|
|
322
|
+
val priorityString = obj.getString("priority", "default")
|
|
323
|
+
|
|
324
|
+
return NotificationPreferences(
|
|
325
|
+
title = obj.getString("title"),
|
|
326
|
+
description = obj.getString("description"),
|
|
327
|
+
iconName = obj.getString("iconName"),
|
|
328
|
+
soundEnabled = obj.getBoolean("soundEnabled", true),
|
|
329
|
+
vibrationEnabled = obj.getBoolean("vibrationEnabled", true),
|
|
330
|
+
showActions = obj.getBoolean("showActions", true),
|
|
331
|
+
actionLabels = actionLabelsObj?.let { ActionLabels.fromJSObject(it) } ?: ActionLabels.default(),
|
|
332
|
+
channelId = obj.getString("channelId"),
|
|
333
|
+
channelName = obj.getString("channelName"),
|
|
334
|
+
priority = NotificationPriority.fromString(priorityString)
|
|
335
|
+
)
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
data class ActionLabels(
|
|
341
|
+
val updateNow: String? = null,
|
|
342
|
+
val updateLater: String? = null,
|
|
343
|
+
val dismiss: String? = null
|
|
344
|
+
) {
|
|
345
|
+
companion object {
|
|
346
|
+
fun default(): ActionLabels {
|
|
347
|
+
return ActionLabels(
|
|
348
|
+
updateNow = "Update Now",
|
|
349
|
+
updateLater = "Later",
|
|
350
|
+
dismiss = "Dismiss"
|
|
351
|
+
)
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
fun fromJSObject(obj: JSObject): ActionLabels {
|
|
355
|
+
return ActionLabels(
|
|
356
|
+
updateNow = obj.getString("updateNow"),
|
|
357
|
+
updateLater = obj.getString("updateLater"),
|
|
358
|
+
dismiss = obj.getString("dismiss")
|
|
359
|
+
)
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
enum class NotificationPriority(val value: String) {
|
|
365
|
+
MIN("min"),
|
|
366
|
+
LOW("low"),
|
|
367
|
+
DEFAULT("default"),
|
|
368
|
+
HIGH("high"),
|
|
369
|
+
MAX("max");
|
|
370
|
+
|
|
371
|
+
companion object {
|
|
372
|
+
fun fromString(value: String): NotificationPriority {
|
|
373
|
+
return values().find { it.value == value } ?: DEFAULT
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
data class NotificationPermissionStatus(
|
|
379
|
+
val granted: Boolean,
|
|
380
|
+
val canRequest: Boolean,
|
|
381
|
+
val shouldShowRationale: Boolean? = null
|
|
382
|
+
) {
|
|
383
|
+
fun toJSObject(): JSObject {
|
|
384
|
+
val obj = JSObject()
|
|
385
|
+
obj.put("granted", granted)
|
|
386
|
+
obj.put("canRequest", canRequest)
|
|
387
|
+
shouldShowRationale?.let { obj.put("shouldShowRationale", it) }
|
|
388
|
+
return obj
|
|
389
|
+
}
|
|
390
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
package com.aoneahsan.nativeupdate
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Singleton manager to maintain references to plugin instances
|
|
5
|
+
* This allows background workers to access plugin functionality
|
|
6
|
+
*/
|
|
7
|
+
object BackgroundUpdateManager {
|
|
8
|
+
@Volatile
|
|
9
|
+
private var backgroundUpdatePlugin: BackgroundUpdatePlugin? = null
|
|
10
|
+
|
|
11
|
+
@Volatile
|
|
12
|
+
private var liveUpdatePlugin: LiveUpdatePlugin? = null
|
|
13
|
+
|
|
14
|
+
@Volatile
|
|
15
|
+
private var appUpdatePlugin: AppUpdatePlugin? = null
|
|
16
|
+
|
|
17
|
+
fun registerBackgroundUpdatePlugin(plugin: BackgroundUpdatePlugin) {
|
|
18
|
+
backgroundUpdatePlugin = plugin
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
fun registerLiveUpdatePlugin(plugin: LiveUpdatePlugin) {
|
|
22
|
+
liveUpdatePlugin = plugin
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
fun registerAppUpdatePlugin(plugin: AppUpdatePlugin) {
|
|
26
|
+
appUpdatePlugin = plugin
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
fun getBackgroundUpdatePlugin(): BackgroundUpdatePlugin? {
|
|
30
|
+
return backgroundUpdatePlugin
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
fun getLiveUpdatePlugin(): LiveUpdatePlugin? {
|
|
34
|
+
return liveUpdatePlugin
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
fun getAppUpdatePlugin(): AppUpdatePlugin? {
|
|
38
|
+
return appUpdatePlugin
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
fun clear() {
|
|
42
|
+
backgroundUpdatePlugin = null
|
|
43
|
+
liveUpdatePlugin = null
|
|
44
|
+
appUpdatePlugin = null
|
|
45
|
+
}
|
|
46
|
+
}
|