capacitor-push-signal 0.0.1
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/CapacitorPushSignal.podspec +19 -0
- package/Package.swift +36 -0
- package/README.md +271 -0
- package/android/build.gradle +66 -0
- package/android/src/main/AndroidManifest.xml +19 -0
- package/android/src/main/java/com/antonseagull/cap/push/signal/PushModels.kt +15 -0
- package/android/src/main/java/com/antonseagull/cap/push/signal/PushSignalCenter.kt +397 -0
- package/android/src/main/java/com/antonseagull/cap/push/signal/PushSignalInitProvider.kt +34 -0
- package/android/src/main/java/com/antonseagull/cap/push/signal/PushSignalMessagingService.kt +20 -0
- package/android/src/main/java/com/antonseagull/cap/push/signal/PushSignalPlugin.kt +85 -0
- package/android/src/main/res/.gitkeep +0 -0
- package/dist/docs.json +275 -0
- package/dist/esm/definitions.d.ts +19 -0
- package/dist/esm/definitions.js +2 -0
- package/dist/esm/definitions.js.map +1 -0
- package/dist/esm/index.d.ts +2 -0
- package/dist/esm/index.js +2 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/pushSignal.d.ts +8 -0
- package/dist/esm/pushSignal.js +76 -0
- package/dist/esm/pushSignal.js.map +1 -0
- package/dist/esm/types.d.ts +20 -0
- package/dist/esm/types.js +2 -0
- package/dist/esm/types.js.map +1 -0
- package/dist/esm/web.d.ts +8 -0
- package/dist/esm/web.js +13 -0
- package/dist/esm/web.js.map +1 -0
- package/dist/plugin.cjs.js +100 -0
- package/dist/plugin.cjs.js.map +1 -0
- package/dist/plugin.js +103 -0
- package/dist/plugin.js.map +1 -0
- package/ios/Sources/PushSignalCore/PushSignalCenter.m +583 -0
- package/ios/Sources/PushSignalCore/PushSignalLaunchStore.m +38 -0
- package/ios/Sources/PushSignalCore/include/PushSignalCenter.h +26 -0
- package/ios/Sources/PushSignalCore/include/PushSignalLaunchStore.h +21 -0
- package/ios/Sources/PushSignalPlugin/PushSignalPlugin.swift +66 -0
- package/ios/Tests/PushSignalPluginTests/PushSignalTests.swift +9 -0
- package/package.json +80 -0
|
@@ -0,0 +1,397 @@
|
|
|
1
|
+
package com.antonseagull.cap.push.signal
|
|
2
|
+
|
|
3
|
+
import android.app.Activity
|
|
4
|
+
import android.app.Application
|
|
5
|
+
import android.app.NotificationChannel
|
|
6
|
+
import android.app.NotificationManager
|
|
7
|
+
import android.app.PendingIntent
|
|
8
|
+
import android.content.Context
|
|
9
|
+
import android.content.Intent
|
|
10
|
+
import android.os.Build
|
|
11
|
+
import android.os.Bundle
|
|
12
|
+
import android.os.Handler
|
|
13
|
+
import android.os.Looper
|
|
14
|
+
import androidx.activity.ComponentActivity
|
|
15
|
+
import androidx.core.app.NotificationCompat
|
|
16
|
+
import com.google.android.gms.tasks.Tasks
|
|
17
|
+
import com.google.firebase.FirebaseApp
|
|
18
|
+
import com.google.firebase.FirebaseOptions
|
|
19
|
+
import com.google.firebase.messaging.FirebaseMessaging
|
|
20
|
+
import com.google.firebase.messaging.RemoteMessage
|
|
21
|
+
import java.util.Collections
|
|
22
|
+
import java.util.UUID
|
|
23
|
+
import java.util.WeakHashMap
|
|
24
|
+
import java.util.concurrent.CopyOnWriteArrayList
|
|
25
|
+
|
|
26
|
+
internal object PushSignalCenter : Application.ActivityLifecycleCallbacks {
|
|
27
|
+
private const val EXTRA_HANDLED = "pushsignal.handled"
|
|
28
|
+
private const val CHANNEL_ID = "push_signal_default"
|
|
29
|
+
|
|
30
|
+
private val lock = Any()
|
|
31
|
+
private val mainHandler = Handler(Looper.getMainLooper())
|
|
32
|
+
@Volatile private var application: Application? = null
|
|
33
|
+
@Volatile private var currentActivity: Activity? = null
|
|
34
|
+
@Volatile private var onMessage: ((PushMessage) -> Unit)? = null
|
|
35
|
+
@Volatile private var onNotificationPress: ((PushMessage) -> Unit)? = null
|
|
36
|
+
@Volatile private var pendingPress: PushMessage? = null
|
|
37
|
+
private val pendingMessages = CopyOnWriteArrayList<PushMessage>()
|
|
38
|
+
private val registeredActivities = Collections.newSetFromMap(WeakHashMap<Activity, Boolean>())
|
|
39
|
+
@Volatile private var startedActivityCount = 0
|
|
40
|
+
@Volatile private var pendingFirebaseConfig: AndroidFirebaseConfig? = null
|
|
41
|
+
private val initializeWaiters = CopyOnWriteArrayList<(Exception?) -> Unit>()
|
|
42
|
+
|
|
43
|
+
fun attach(context: Context) {
|
|
44
|
+
val app = context.applicationContext as? Application ?: return
|
|
45
|
+
if (application === app) {
|
|
46
|
+
return
|
|
47
|
+
}
|
|
48
|
+
application?.unregisterActivityLifecycleCallbacks(this)
|
|
49
|
+
application = app
|
|
50
|
+
app.registerActivityLifecycleCallbacks(this)
|
|
51
|
+
app.currentActivityOrNull()?.let { activity ->
|
|
52
|
+
currentActivity = activity
|
|
53
|
+
registerActivity(activity)
|
|
54
|
+
handleIntent(activity.intent)
|
|
55
|
+
}
|
|
56
|
+
pendingFirebaseConfig?.let { config ->
|
|
57
|
+
pendingFirebaseConfig = null
|
|
58
|
+
finishInitialize(applyFirebaseConfig(app, config))
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
fun initialize(config: AndroidFirebaseConfig, onDone: (Exception?) -> Unit) {
|
|
63
|
+
if (!config.hasRequiredFields()) {
|
|
64
|
+
onDone(null)
|
|
65
|
+
return
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
val context = application
|
|
69
|
+
if (context == null) {
|
|
70
|
+
pendingFirebaseConfig = config
|
|
71
|
+
initializeWaiters.add(onDone)
|
|
72
|
+
return
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
onDone(applyFirebaseConfig(context, config))
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
fun setOnMessage(callback: (PushMessage) -> Unit) {
|
|
79
|
+
onMessage = callback
|
|
80
|
+
val queued = pendingMessages.toList()
|
|
81
|
+
pendingMessages.clear()
|
|
82
|
+
queued.forEach { message ->
|
|
83
|
+
runOnMain { deliverMessage(message) }
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
fun setOnNotificationPress(callback: (PushMessage) -> Unit) {
|
|
88
|
+
onNotificationPress = callback
|
|
89
|
+
val pending = synchronized(lock) {
|
|
90
|
+
val message = pendingPress
|
|
91
|
+
pendingPress = null
|
|
92
|
+
message
|
|
93
|
+
}
|
|
94
|
+
if (pending != null) {
|
|
95
|
+
callback(pending)
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
fun fetchToken(): String {
|
|
100
|
+
val context = application
|
|
101
|
+
?: throw IllegalStateException("PushSignal is not initialized")
|
|
102
|
+
|
|
103
|
+
try {
|
|
104
|
+
if (FirebaseApp.getApps(context).isEmpty()) {
|
|
105
|
+
FirebaseApp.initializeApp(context)
|
|
106
|
+
}
|
|
107
|
+
FirebaseApp.getInstance()
|
|
108
|
+
} catch (error: IllegalStateException) {
|
|
109
|
+
throw IllegalStateException(
|
|
110
|
+
"Firebase is not configured. Call initialize({ project_id, mobilesdk_app_id, current_key, project_number }) or add google-services.json.",
|
|
111
|
+
error
|
|
112
|
+
)
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
val task = FirebaseMessaging.getInstance().token
|
|
116
|
+
val token = try {
|
|
117
|
+
Tasks.await(task)
|
|
118
|
+
} catch (error: Exception) {
|
|
119
|
+
throw IllegalStateException(
|
|
120
|
+
"Failed to get an FCM token. Call initialize({ project_id, mobilesdk_app_id, current_key, project_number }) or add google-services.json.",
|
|
121
|
+
error
|
|
122
|
+
)
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (token.isNullOrEmpty()) {
|
|
126
|
+
throw IllegalStateException("Firebase returned an empty FCM token")
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return token
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
fun emitMessage(remoteMessage: RemoteMessage) {
|
|
133
|
+
val message = remoteMessage.toPushMessage()
|
|
134
|
+
runOnMain { deliverMessage(message) }
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
private fun deliverMessage(message: PushMessage) {
|
|
138
|
+
val callback = onMessage
|
|
139
|
+
if (callback == null) {
|
|
140
|
+
pendingMessages.add(message)
|
|
141
|
+
return
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
try {
|
|
145
|
+
callback(message)
|
|
146
|
+
} catch (_: Throwable) {
|
|
147
|
+
// Ignore listener failures.
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
val inForeground = startedActivityCount > 0 || currentActivity != null
|
|
151
|
+
if (
|
|
152
|
+
inForeground &&
|
|
153
|
+
(!message.title.isNullOrEmpty() || !message.body.isNullOrEmpty())
|
|
154
|
+
) {
|
|
155
|
+
postForegroundNotification(message)
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
private fun runOnMain(block: () -> Unit) {
|
|
160
|
+
if (Looper.myLooper() == Looper.getMainLooper()) {
|
|
161
|
+
block()
|
|
162
|
+
} else {
|
|
163
|
+
mainHandler.post(block)
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
private fun postForegroundNotification(message: PushMessage) {
|
|
168
|
+
val context = application ?: return
|
|
169
|
+
val manager = context.getSystemService(Context.NOTIFICATION_SERVICE) as? NotificationManager
|
|
170
|
+
?: return
|
|
171
|
+
|
|
172
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
173
|
+
val existing = manager.getNotificationChannel(CHANNEL_ID)
|
|
174
|
+
if (existing == null) {
|
|
175
|
+
manager.createNotificationChannel(
|
|
176
|
+
NotificationChannel(
|
|
177
|
+
CHANNEL_ID,
|
|
178
|
+
"Notifications",
|
|
179
|
+
NotificationManager.IMPORTANCE_HIGH
|
|
180
|
+
)
|
|
181
|
+
)
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
val launchIntent = context.packageManager.getLaunchIntentForPackage(context.packageName)
|
|
186
|
+
?: return
|
|
187
|
+
launchIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_CLEAR_TOP)
|
|
188
|
+
launchIntent.putExtra("google.message_id", message.id ?: UUID.randomUUID().toString())
|
|
189
|
+
message.title?.let { launchIntent.putExtra("gcm.notification.title", it) }
|
|
190
|
+
message.body?.let { launchIntent.putExtra("gcm.notification.body", it) }
|
|
191
|
+
message.data.forEach { (key, value) ->
|
|
192
|
+
launchIntent.putExtra(key, value)
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
val requestCode = (message.id ?: message.title ?: "push").hashCode()
|
|
196
|
+
val pendingIntent = PendingIntent.getActivity(
|
|
197
|
+
context,
|
|
198
|
+
requestCode,
|
|
199
|
+
launchIntent,
|
|
200
|
+
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
val builder = NotificationCompat.Builder(context, CHANNEL_ID)
|
|
204
|
+
.setSmallIcon(smallIcon(context))
|
|
205
|
+
.setContentTitle(message.title.orEmpty())
|
|
206
|
+
.setContentText(message.body.orEmpty())
|
|
207
|
+
.setContentIntent(pendingIntent)
|
|
208
|
+
.setAutoCancel(true)
|
|
209
|
+
.setPriority(NotificationCompat.PRIORITY_HIGH)
|
|
210
|
+
.setDefaults(NotificationCompat.DEFAULT_SOUND)
|
|
211
|
+
.setNumber(1)
|
|
212
|
+
|
|
213
|
+
manager.notify(requestCode, builder.build())
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
private fun smallIcon(context: Context): Int {
|
|
217
|
+
val named = context.resources.getIdentifier("ic_notification", "drawable", context.packageName)
|
|
218
|
+
if (named != 0) {
|
|
219
|
+
return named
|
|
220
|
+
}
|
|
221
|
+
val appIcon = context.applicationInfo.icon
|
|
222
|
+
if (appIcon != 0) {
|
|
223
|
+
return appIcon
|
|
224
|
+
}
|
|
225
|
+
return android.R.drawable.stat_notify_more
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
|
|
229
|
+
currentActivity = activity
|
|
230
|
+
registerActivity(activity)
|
|
231
|
+
handleIntent(activity.intent)
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
override fun onActivityStarted(activity: Activity) {
|
|
235
|
+
currentActivity = activity
|
|
236
|
+
startedActivityCount += 1
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
override fun onActivityResumed(activity: Activity) {
|
|
240
|
+
currentActivity = activity
|
|
241
|
+
handleIntent(activity.intent)
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
override fun onActivityPaused(activity: Activity) {
|
|
245
|
+
if (currentActivity === activity) {
|
|
246
|
+
currentActivity = null
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
override fun onActivityStopped(activity: Activity) {
|
|
251
|
+
startedActivityCount = (startedActivityCount - 1).coerceAtLeast(0)
|
|
252
|
+
if (currentActivity === activity) {
|
|
253
|
+
currentActivity = null
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) = Unit
|
|
258
|
+
|
|
259
|
+
override fun onActivityDestroyed(activity: Activity) {
|
|
260
|
+
if (currentActivity === activity) {
|
|
261
|
+
currentActivity = null
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
private fun registerActivity(activity: Activity) {
|
|
266
|
+
if (!registeredActivities.add(activity)) {
|
|
267
|
+
return
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
val componentActivity = activity as? ComponentActivity ?: return
|
|
271
|
+
componentActivity.addOnNewIntentListener { intent ->
|
|
272
|
+
handleIntent(intent)
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
private fun handleIntent(intent: Intent?) {
|
|
277
|
+
if (intent == null || !intent.isPushTap() || intent.getBooleanExtra(EXTRA_HANDLED, false)) {
|
|
278
|
+
return
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
intent.putExtra(EXTRA_HANDLED, true)
|
|
282
|
+
emitPress(intent.toPushMessage())
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
private fun applyFirebaseConfig(context: Context, config: AndroidFirebaseConfig): Exception? {
|
|
286
|
+
if (FirebaseApp.getApps(context).isNotEmpty()) {
|
|
287
|
+
FirebaseMessaging.getInstance().isAutoInitEnabled = true
|
|
288
|
+
return null
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
if (!config.hasRequiredFields()) {
|
|
292
|
+
return null
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
return try {
|
|
296
|
+
val options =
|
|
297
|
+
FirebaseOptions.Builder()
|
|
298
|
+
.setProjectId(config.project_id!!.trim())
|
|
299
|
+
.setApplicationId(config.mobilesdk_app_id!!.trim())
|
|
300
|
+
.setApiKey(config.current_key!!.trim())
|
|
301
|
+
.setGcmSenderId(config.project_number!!.trim())
|
|
302
|
+
.build()
|
|
303
|
+
FirebaseApp.initializeApp(context, options)
|
|
304
|
+
FirebaseMessaging.getInstance().isAutoInitEnabled = true
|
|
305
|
+
null
|
|
306
|
+
} catch (error: Exception) {
|
|
307
|
+
error
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
private fun finishInitialize(error: Exception?) {
|
|
312
|
+
val waiters = initializeWaiters.toList()
|
|
313
|
+
initializeWaiters.clear()
|
|
314
|
+
waiters.forEach { it(error) }
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
private fun emitPress(message: PushMessage) {
|
|
318
|
+
val listener = onNotificationPress
|
|
319
|
+
if (listener != null) {
|
|
320
|
+
listener(message)
|
|
321
|
+
} else {
|
|
322
|
+
synchronized(lock) {
|
|
323
|
+
pendingPress = message
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
private fun Application.currentActivityOrNull(): Activity? {
|
|
330
|
+
return try {
|
|
331
|
+
val activityThreadClass = Class.forName("android.app.ActivityThread")
|
|
332
|
+
val activityThread = activityThreadClass.getMethod("currentActivityThread").invoke(null)
|
|
333
|
+
val activitiesField = activityThreadClass.getDeclaredField("mActivities")
|
|
334
|
+
activitiesField.isAccessible = true
|
|
335
|
+
val activities = activitiesField.get(activityThread) as Map<*, *>
|
|
336
|
+
activities.values.firstNotNullOfOrNull { record ->
|
|
337
|
+
val recordClass = record?.javaClass ?: return@firstNotNullOfOrNull null
|
|
338
|
+
val paused = recordClass.getDeclaredField("paused").apply { isAccessible = true }.getBoolean(record)
|
|
339
|
+
if (paused) {
|
|
340
|
+
return@firstNotNullOfOrNull null
|
|
341
|
+
}
|
|
342
|
+
recordClass.getDeclaredField("activity").apply { isAccessible = true }.get(record) as? Activity
|
|
343
|
+
}
|
|
344
|
+
} catch (_: Exception) {
|
|
345
|
+
null
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
private fun Intent.isPushTap(): Boolean {
|
|
350
|
+
val extras = extras ?: return false
|
|
351
|
+
return extras.containsKey("google.message_id") ||
|
|
352
|
+
extras.containsKey("google.sent_time") ||
|
|
353
|
+
extras.containsKey("gcm.n.e") ||
|
|
354
|
+
extras.containsKey("gcm.notification.title")
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
private fun Intent.toPushMessage(): PushMessage {
|
|
358
|
+
val extras = extras ?: Bundle()
|
|
359
|
+
val data = linkedMapOf<String, String>()
|
|
360
|
+
for (key in extras.keySet()) {
|
|
361
|
+
if (key.startsWith("google.") || key.startsWith("gcm.") || key == EXTRA_HANDLED_KEY) {
|
|
362
|
+
continue
|
|
363
|
+
}
|
|
364
|
+
@Suppress("DEPRECATION")
|
|
365
|
+
val value = extras.get(key) ?: continue
|
|
366
|
+
data[key] = value.toString()
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
return PushMessage(
|
|
370
|
+
extras.getString("google.message_id"),
|
|
371
|
+
extras.getString("gcm.n.title")
|
|
372
|
+
?: extras.getString("gcm.notification.title")
|
|
373
|
+
?: extras.getString("title"),
|
|
374
|
+
extras.getString("gcm.n.body")
|
|
375
|
+
?: extras.getString("gcm.notification.body")
|
|
376
|
+
?: extras.getString("body"),
|
|
377
|
+
data
|
|
378
|
+
)
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
private fun AndroidFirebaseConfig.hasRequiredFields(): Boolean {
|
|
382
|
+
return !project_id.isNullOrBlank() &&
|
|
383
|
+
!mobilesdk_app_id.isNullOrBlank() &&
|
|
384
|
+
!current_key.isNullOrBlank() &&
|
|
385
|
+
!project_number.isNullOrBlank()
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
private const val EXTRA_HANDLED_KEY = "pushsignal.handled"
|
|
389
|
+
|
|
390
|
+
internal fun RemoteMessage.toPushMessage(): PushMessage {
|
|
391
|
+
return PushMessage(
|
|
392
|
+
messageId,
|
|
393
|
+
notification?.title,
|
|
394
|
+
notification?.body,
|
|
395
|
+
data
|
|
396
|
+
)
|
|
397
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
package com.antonseagull.cap.push.signal
|
|
2
|
+
|
|
3
|
+
import android.content.ContentProvider
|
|
4
|
+
import android.content.ContentValues
|
|
5
|
+
import android.database.Cursor
|
|
6
|
+
import android.net.Uri
|
|
7
|
+
|
|
8
|
+
class PushSignalInitProvider : ContentProvider() {
|
|
9
|
+
override fun onCreate(): Boolean {
|
|
10
|
+
context?.let(PushSignalCenter::attach)
|
|
11
|
+
return true
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
override fun query(
|
|
15
|
+
uri: Uri,
|
|
16
|
+
projection: Array<out String>?,
|
|
17
|
+
selection: String?,
|
|
18
|
+
selectionArgs: Array<out String>?,
|
|
19
|
+
sortOrder: String?
|
|
20
|
+
): Cursor? = null
|
|
21
|
+
|
|
22
|
+
override fun getType(uri: Uri): String? = null
|
|
23
|
+
|
|
24
|
+
override fun insert(uri: Uri, values: ContentValues?): Uri? = null
|
|
25
|
+
|
|
26
|
+
override fun delete(uri: Uri, selection: String?, selectionArgs: Array<out String>?): Int = 0
|
|
27
|
+
|
|
28
|
+
override fun update(
|
|
29
|
+
uri: Uri,
|
|
30
|
+
values: ContentValues?,
|
|
31
|
+
selection: String?,
|
|
32
|
+
selectionArgs: Array<out String>?
|
|
33
|
+
): Int = 0
|
|
34
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
package com.antonseagull.cap.push.signal
|
|
2
|
+
|
|
3
|
+
import com.google.firebase.messaging.FirebaseMessagingService
|
|
4
|
+
import com.google.firebase.messaging.RemoteMessage
|
|
5
|
+
|
|
6
|
+
class PushSignalMessagingService : FirebaseMessagingService() {
|
|
7
|
+
override fun onCreate() {
|
|
8
|
+
super.onCreate()
|
|
9
|
+
PushSignalCenter.attach(applicationContext)
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
override fun onNewToken(token: String) {
|
|
13
|
+
PushSignalCenter.attach(applicationContext)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
override fun onMessageReceived(message: RemoteMessage) {
|
|
17
|
+
PushSignalCenter.attach(applicationContext)
|
|
18
|
+
PushSignalCenter.emitMessage(message)
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
package com.antonseagull.cap.push.signal
|
|
2
|
+
|
|
3
|
+
import com.getcapacitor.JSObject
|
|
4
|
+
import com.getcapacitor.Plugin
|
|
5
|
+
import com.getcapacitor.PluginCall
|
|
6
|
+
import com.getcapacitor.PluginMethod
|
|
7
|
+
import com.getcapacitor.annotation.CapacitorPlugin
|
|
8
|
+
import java.util.concurrent.Executors
|
|
9
|
+
|
|
10
|
+
@CapacitorPlugin(name = "PushSignal")
|
|
11
|
+
class PushSignalPlugin : Plugin() {
|
|
12
|
+
@Volatile
|
|
13
|
+
private var listening = false
|
|
14
|
+
|
|
15
|
+
private val executor = Executors.newSingleThreadExecutor()
|
|
16
|
+
|
|
17
|
+
override fun load() {
|
|
18
|
+
PushSignalCenter.attach(context)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
@PluginMethod
|
|
22
|
+
fun initialize(call: PluginCall) {
|
|
23
|
+
val config =
|
|
24
|
+
AndroidFirebaseConfig(
|
|
25
|
+
project_id = call.getString("project_id"),
|
|
26
|
+
mobilesdk_app_id = call.getString("mobilesdk_app_id"),
|
|
27
|
+
current_key = call.getString("current_key"),
|
|
28
|
+
project_number = call.getString("project_number"),
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
PushSignalCenter.attach(context)
|
|
32
|
+
PushSignalCenter.initialize(config) { error ->
|
|
33
|
+
if (error == null) {
|
|
34
|
+
call.resolve()
|
|
35
|
+
} else {
|
|
36
|
+
call.reject(error.message, error)
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
@PluginMethod
|
|
42
|
+
fun getCredentials(call: PluginCall) {
|
|
43
|
+
executor.execute {
|
|
44
|
+
try {
|
|
45
|
+
PushSignalCenter.attach(context)
|
|
46
|
+
val token = PushSignalCenter.fetchToken()
|
|
47
|
+
val result =
|
|
48
|
+
JSObject().apply {
|
|
49
|
+
put("platform", "android")
|
|
50
|
+
put("token", token)
|
|
51
|
+
}
|
|
52
|
+
call.resolve(result)
|
|
53
|
+
} catch (error: Exception) {
|
|
54
|
+
call.reject(error.message, error)
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
@PluginMethod
|
|
60
|
+
fun startListening(call: PluginCall) {
|
|
61
|
+
if (!listening) {
|
|
62
|
+
listening = true
|
|
63
|
+
PushSignalCenter.setOnMessage { message ->
|
|
64
|
+
notifyListeners("onMessage", message.toJSObject())
|
|
65
|
+
}
|
|
66
|
+
PushSignalCenter.setOnNotificationPress { message ->
|
|
67
|
+
notifyListeners("onNotificationPress", message.toJSObject())
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
call.resolve()
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
private fun PushMessage.toJSObject(): JSObject {
|
|
75
|
+
val map = JSObject()
|
|
76
|
+
id?.let { map.put("id", it) }
|
|
77
|
+
title?.let { map.put("title", it) }
|
|
78
|
+
body?.let { map.put("body", it) }
|
|
79
|
+
val dataMap = JSObject()
|
|
80
|
+
data.forEach { (key, value) ->
|
|
81
|
+
dataMap.put(key, value)
|
|
82
|
+
}
|
|
83
|
+
map.put("data", dataMap)
|
|
84
|
+
return map
|
|
85
|
+
}
|
|
File without changes
|