react-native-push-signal 0.1.2 → 0.1.3
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/README.md +1 -1
- package/README.ru.md +1 -1
- package/android/build.gradle +1 -0
- package/android/consumer-rules.pro +4 -0
- package/android/src/main/java/com/margelo/nitro/pushsignal/PushSignalCenter.kt +58 -14
- package/android/src/main/java/com/margelo/nitro/pushsignal/PushSignalMessagingService.kt +5 -0
- package/ios/PushSignalCenter.swift +185 -22
- package/ios/PushSignalLaunchStore.m +15 -0
- package/lib/module/pushSignal.native.js +3 -1
- package/lib/module/pushSignal.native.js.map +1 -1
- package/lib/typescript/src/pushSignal.native.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/pushSignal.native.tsx +4 -1
package/README.md
CHANGED
|
@@ -74,7 +74,7 @@ Keep Apple `.p8` keys and the Firebase service account on the server. The app ne
|
|
|
74
74
|
2. Enable **Background Modes → Remote notifications**.
|
|
75
75
|
3. Use a physical device. The simulator cannot register with APNs.
|
|
76
76
|
|
|
77
|
-
The library hooks `UNUserNotificationCenter` and APNs token callbacks, so the host `AppDelegate` does not need extra code.
|
|
77
|
+
The library hooks `UNUserNotificationCenter` at launch (before JS starts) and APNs token callbacks, so the host `AppDelegate` does not need extra code. Foreground pushes only reach JS if this delegate is installed before launch finishes.
|
|
78
78
|
|
|
79
79
|
## Android setup
|
|
80
80
|
|
package/README.ru.md
CHANGED
|
@@ -74,7 +74,7 @@ const stopPress = onNotificationPress((message) => {
|
|
|
74
74
|
2. Включите **Background Modes → Remote notifications**.
|
|
75
75
|
3. Проверяйте на физическом устройстве. Симулятор не умеет регистрироваться в APNs.
|
|
76
76
|
|
|
77
|
-
Библиотека сама
|
|
77
|
+
Библиотека сама ставит делегат `UNUserNotificationCenter` на запуске (до JS) и подписывается на колбеки APNs-токена. В `AppDelegate` хоста ничего дописывать не нужно. Без делегата до конца запуска iOS не вызывает `willPresent`, и пуш в foreground не доходит до JS.
|
|
78
78
|
|
|
79
79
|
## Настройка Android
|
|
80
80
|
|
package/android/build.gradle
CHANGED
|
@@ -37,7 +37,9 @@ internal object PushSignalCenter : Application.ActivityLifecycleCallbacks {
|
|
|
37
37
|
@Volatile private var onMessage: ((PushMessage) -> Promise<Promise<Boolean>>)? = null
|
|
38
38
|
@Volatile private var onNotificationPress: ((PushMessage) -> Unit)? = null
|
|
39
39
|
@Volatile private var pendingPress: PushMessage? = null
|
|
40
|
+
private val pendingMessages = CopyOnWriteArrayList<PushMessage>()
|
|
40
41
|
private val registeredActivities = Collections.newSetFromMap(WeakHashMap<Activity, Boolean>())
|
|
42
|
+
@Volatile private var startedActivityCount = 0
|
|
41
43
|
@Volatile private var pendingFirebaseConfig: AndroidFirebaseConfig? = null
|
|
42
44
|
private val initializeWaiters = CopyOnWriteArrayList<(Exception?) -> Unit>()
|
|
43
45
|
|
|
@@ -78,6 +80,22 @@ internal object PushSignalCenter : Application.ActivityLifecycleCallbacks {
|
|
|
78
80
|
|
|
79
81
|
fun setOnMessage(callback: (PushMessage) -> Promise<Promise<Boolean>>) {
|
|
80
82
|
onMessage = callback
|
|
83
|
+
val queued = pendingMessages.toList()
|
|
84
|
+
pendingMessages.clear()
|
|
85
|
+
queued.forEach { message ->
|
|
86
|
+
runOnMain {
|
|
87
|
+
val inForeground = startedActivityCount > 0 || currentActivity != null
|
|
88
|
+
resolveShouldShowBanner(message) { shouldShow ->
|
|
89
|
+
if (
|
|
90
|
+
shouldShow &&
|
|
91
|
+
inForeground &&
|
|
92
|
+
(!message.title.isNullOrEmpty() || !message.body.isNullOrEmpty())
|
|
93
|
+
) {
|
|
94
|
+
postForegroundNotification(message)
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
81
99
|
}
|
|
82
100
|
|
|
83
101
|
fun setOnNotificationPress(callback: (PushMessage) -> Unit) {
|
|
@@ -127,18 +145,34 @@ internal object PushSignalCenter : Application.ActivityLifecycleCallbacks {
|
|
|
127
145
|
|
|
128
146
|
fun emitMessage(remoteMessage: RemoteMessage) {
|
|
129
147
|
val message = remoteMessage.toPushMessage()
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
if (
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
148
|
+
runOnMain {
|
|
149
|
+
val callback = onMessage
|
|
150
|
+
if (callback == null) {
|
|
151
|
+
pendingMessages.add(message)
|
|
152
|
+
return@runOnMain
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
val inForeground = startedActivityCount > 0 || currentActivity != null
|
|
156
|
+
resolveShouldShowBanner(message) { shouldShow ->
|
|
157
|
+
if (
|
|
158
|
+
shouldShow &&
|
|
159
|
+
inForeground &&
|
|
160
|
+
(!message.title.isNullOrEmpty() || !message.body.isNullOrEmpty())
|
|
161
|
+
) {
|
|
162
|
+
postForegroundNotification(message)
|
|
163
|
+
}
|
|
138
164
|
}
|
|
139
165
|
}
|
|
140
166
|
}
|
|
141
167
|
|
|
168
|
+
private fun runOnMain(block: () -> Unit) {
|
|
169
|
+
if (Looper.myLooper() == Looper.getMainLooper()) {
|
|
170
|
+
block()
|
|
171
|
+
} else {
|
|
172
|
+
mainHandler.post(block)
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
142
176
|
private fun resolveShouldShowBanner(
|
|
143
177
|
message: PushMessage,
|
|
144
178
|
onDone: (Boolean) -> Unit
|
|
@@ -152,7 +186,7 @@ internal object PushSignalCenter : Application.ActivityLifecycleCallbacks {
|
|
|
152
186
|
val delivered = AtomicBoolean(false)
|
|
153
187
|
val timeout = Runnable {
|
|
154
188
|
if (delivered.compareAndSet(false, true)) {
|
|
155
|
-
onDone(
|
|
189
|
+
onDone(true)
|
|
156
190
|
}
|
|
157
191
|
}
|
|
158
192
|
mainHandler.postDelayed(timeout, FOREGROUND_TIMEOUT_MS)
|
|
@@ -169,11 +203,11 @@ internal object PushSignalCenter : Application.ActivityLifecycleCallbacks {
|
|
|
169
203
|
.then { inner ->
|
|
170
204
|
inner
|
|
171
205
|
.then { shouldShow -> finish(shouldShow) }
|
|
172
|
-
.catch { finish(
|
|
206
|
+
.catch { finish(true) }
|
|
173
207
|
}
|
|
174
|
-
.catch { finish(
|
|
208
|
+
.catch { finish(true) }
|
|
175
209
|
} catch (_: Throwable) {
|
|
176
|
-
finish(
|
|
210
|
+
finish(true)
|
|
177
211
|
}
|
|
178
212
|
}
|
|
179
213
|
|
|
@@ -244,7 +278,10 @@ internal object PushSignalCenter : Application.ActivityLifecycleCallbacks {
|
|
|
244
278
|
handleIntent(activity.intent)
|
|
245
279
|
}
|
|
246
280
|
|
|
247
|
-
override fun onActivityStarted(activity: Activity)
|
|
281
|
+
override fun onActivityStarted(activity: Activity) {
|
|
282
|
+
currentActivity = activity
|
|
283
|
+
startedActivityCount += 1
|
|
284
|
+
}
|
|
248
285
|
|
|
249
286
|
override fun onActivityResumed(activity: Activity) {
|
|
250
287
|
currentActivity = activity
|
|
@@ -257,7 +294,12 @@ internal object PushSignalCenter : Application.ActivityLifecycleCallbacks {
|
|
|
257
294
|
}
|
|
258
295
|
}
|
|
259
296
|
|
|
260
|
-
override fun onActivityStopped(activity: Activity)
|
|
297
|
+
override fun onActivityStopped(activity: Activity) {
|
|
298
|
+
startedActivityCount = (startedActivityCount - 1).coerceAtLeast(0)
|
|
299
|
+
if (currentActivity === activity) {
|
|
300
|
+
currentActivity = null
|
|
301
|
+
}
|
|
302
|
+
}
|
|
261
303
|
|
|
262
304
|
override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) = Unit
|
|
263
305
|
|
|
@@ -289,6 +331,7 @@ internal object PushSignalCenter : Application.ActivityLifecycleCallbacks {
|
|
|
289
331
|
|
|
290
332
|
private fun applyFirebaseConfig(context: Context, config: AndroidFirebaseConfig): Exception? {
|
|
291
333
|
if (FirebaseApp.getApps(context).isNotEmpty()) {
|
|
334
|
+
FirebaseMessaging.getInstance().isAutoInitEnabled = true
|
|
292
335
|
return null
|
|
293
336
|
}
|
|
294
337
|
|
|
@@ -305,6 +348,7 @@ internal object PushSignalCenter : Application.ActivityLifecycleCallbacks {
|
|
|
305
348
|
.setGcmSenderId(config.project_number!!.trim())
|
|
306
349
|
.build()
|
|
307
350
|
FirebaseApp.initializeApp(context, options)
|
|
351
|
+
FirebaseMessaging.getInstance().isAutoInitEnabled = true
|
|
308
352
|
null
|
|
309
353
|
} catch (error: Exception) {
|
|
310
354
|
error
|
|
@@ -9,7 +9,12 @@ class PushSignalMessagingService : FirebaseMessagingService() {
|
|
|
9
9
|
PushSignalCenter.attach(applicationContext)
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
+
override fun onNewToken(token: String) {
|
|
13
|
+
PushSignalCenter.attach(applicationContext)
|
|
14
|
+
}
|
|
15
|
+
|
|
12
16
|
override fun onMessageReceived(message: RemoteMessage) {
|
|
17
|
+
PushSignalCenter.attach(applicationContext)
|
|
13
18
|
PushSignalCenter.emitMessage(message)
|
|
14
19
|
}
|
|
15
20
|
}
|
|
@@ -13,16 +13,31 @@ final class PushSignalCenter: NSObject, UNUserNotificationCenterDelegate {
|
|
|
13
13
|
shared.install()
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
+
/// Called from ObjC `+load` / launch notifications so the UNUserNotificationCenter
|
|
17
|
+
/// delegate is set before the app finishes launching. If this happens after JS loads,
|
|
18
|
+
/// iOS never calls `willPresent` and foreground pushes never reach JS.
|
|
19
|
+
@objc static func installEarly() {
|
|
20
|
+
shared.install()
|
|
21
|
+
}
|
|
22
|
+
|
|
16
23
|
private let lock = NSLock()
|
|
17
24
|
private var didInstall = false
|
|
25
|
+
private var didSwizzleNotificationCenter = false
|
|
18
26
|
private var deviceToken: String?
|
|
19
27
|
private var registrationError: Error?
|
|
20
28
|
private var tokenWaiters: [(Result<String, Error>) -> Void] = []
|
|
21
29
|
private var pendingPress: PushMessage?
|
|
30
|
+
private var pendingMessages: [PushMessage] = []
|
|
22
31
|
private var pendingLaunchOptions: [AnyHashable: Any]?
|
|
23
32
|
private var didCaptureLaunchNotification = false
|
|
33
|
+
private var recentMessageIds: [String: Date] = [:]
|
|
34
|
+
private weak var forwardingDelegate: UNUserNotificationCenterDelegate?
|
|
24
35
|
|
|
25
|
-
var onMessage: ((PushMessage) -> Promise<Promise<Bool>>)?
|
|
36
|
+
var onMessage: ((PushMessage) -> Promise<Promise<Bool>>)? {
|
|
37
|
+
didSet {
|
|
38
|
+
flushPendingMessages()
|
|
39
|
+
}
|
|
40
|
+
}
|
|
26
41
|
var onNotificationPress: ((PushMessage) -> Void)? {
|
|
27
42
|
didSet {
|
|
28
43
|
flushPendingPress()
|
|
@@ -30,13 +45,21 @@ final class PushSignalCenter: NSObject, UNUserNotificationCenterDelegate {
|
|
|
30
45
|
}
|
|
31
46
|
|
|
32
47
|
func install() {
|
|
33
|
-
|
|
34
|
-
|
|
48
|
+
if Thread.isMainThread {
|
|
49
|
+
installOnMain()
|
|
50
|
+
} else {
|
|
51
|
+
DispatchQueue.main.async {
|
|
52
|
+
self.installOnMain()
|
|
53
|
+
}
|
|
35
54
|
}
|
|
36
55
|
}
|
|
37
56
|
|
|
38
57
|
private func installOnMain() {
|
|
58
|
+
swizzleNotificationCenterDelegateIfNeeded()
|
|
59
|
+
|
|
39
60
|
guard !didInstall else {
|
|
61
|
+
UNUserNotificationCenter.current().delegate = self
|
|
62
|
+
swizzleAppDelegate()
|
|
40
63
|
captureLaunchNotificationIfNeeded()
|
|
41
64
|
return
|
|
42
65
|
}
|
|
@@ -47,6 +70,12 @@ final class PushSignalCenter: NSObject, UNUserNotificationCenterDelegate {
|
|
|
47
70
|
captureLaunchNotificationIfNeeded()
|
|
48
71
|
}
|
|
49
72
|
|
|
73
|
+
func rememberForwardingDelegate(_ delegate: UNUserNotificationCenterDelegate?) {
|
|
74
|
+
if let delegate, delegate !== self {
|
|
75
|
+
forwardingDelegate = delegate
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
50
79
|
func fetchCredentials() async throws -> PushCredentials {
|
|
51
80
|
await MainActor.run {
|
|
52
81
|
self.installOnMain()
|
|
@@ -70,25 +99,39 @@ final class PushSignalCenter: NSObject, UNUserNotificationCenterDelegate {
|
|
|
70
99
|
finishRegistration(result: .failure(error))
|
|
71
100
|
}
|
|
72
101
|
|
|
73
|
-
func userNotificationCenter(
|
|
102
|
+
@objc func userNotificationCenter(
|
|
74
103
|
_ center: UNUserNotificationCenter,
|
|
75
104
|
willPresent notification: UNNotification,
|
|
76
105
|
withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void
|
|
77
106
|
) {
|
|
78
107
|
let message = Self.message(from: notification)
|
|
79
108
|
Task {
|
|
80
|
-
let shouldShow = await self.
|
|
81
|
-
|
|
109
|
+
let shouldShow = await self.deliverMessage(message)
|
|
110
|
+
let ours: UNNotificationPresentationOptions = shouldShow ? Self.foregroundPresentationOptions : []
|
|
111
|
+
await MainActor.run {
|
|
112
|
+
self.forwardWillPresent(
|
|
113
|
+
center,
|
|
114
|
+
notification: notification,
|
|
115
|
+
ourOptions: ours,
|
|
116
|
+
completionHandler: completionHandler
|
|
117
|
+
)
|
|
118
|
+
}
|
|
82
119
|
}
|
|
83
120
|
}
|
|
84
121
|
|
|
85
|
-
func userNotificationCenter(
|
|
122
|
+
@objc func userNotificationCenter(
|
|
86
123
|
_ center: UNUserNotificationCenter,
|
|
87
124
|
didReceive response: UNNotificationResponse,
|
|
88
125
|
withCompletionHandler completionHandler: @escaping () -> Void
|
|
89
126
|
) {
|
|
90
127
|
emitPress(Self.message(from: response.notification))
|
|
91
|
-
|
|
128
|
+
if forwardingDelegate?.responds(
|
|
129
|
+
to: #selector(UNUserNotificationCenterDelegate.userNotificationCenter(_:didReceive:withCompletionHandler:))
|
|
130
|
+
) == true {
|
|
131
|
+
forwardingDelegate?.userNotificationCenter?(center, didReceive: response, withCompletionHandler: completionHandler)
|
|
132
|
+
} else {
|
|
133
|
+
completionHandler()
|
|
134
|
+
}
|
|
92
135
|
}
|
|
93
136
|
|
|
94
137
|
private func waitForToken() async throws -> String {
|
|
@@ -156,29 +199,118 @@ final class PushSignalCenter: NSObject, UNUserNotificationCenterDelegate {
|
|
|
156
199
|
waiters.forEach { $0(result) }
|
|
157
200
|
}
|
|
158
201
|
|
|
159
|
-
private func
|
|
160
|
-
|
|
202
|
+
private func synchronized<T>(_ body: () -> T) -> T {
|
|
203
|
+
lock.lock()
|
|
204
|
+
defer { lock.unlock() }
|
|
205
|
+
return body()
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
private func deliverMessage(_ message: PushMessage) async -> Bool {
|
|
209
|
+
guard shouldEmit(message) else {
|
|
161
210
|
return false
|
|
162
211
|
}
|
|
163
212
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
213
|
+
let callback = synchronized { onMessage }
|
|
214
|
+
|
|
215
|
+
guard let callback else {
|
|
216
|
+
synchronized { pendingMessages.append(message) }
|
|
217
|
+
// Still show the system banner so a visible push is not swallowed
|
|
218
|
+
// before JS has subscribed.
|
|
219
|
+
return true
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
return await invokeOnMessage(callback, message: message)
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
private func invokeOnMessage(
|
|
226
|
+
_ callback: @escaping (PushMessage) -> Promise<Promise<Bool>>,
|
|
227
|
+
message: PushMessage
|
|
228
|
+
) async -> Bool {
|
|
229
|
+
await withCheckedContinuation { continuation in
|
|
230
|
+
let resumeLock = NSLock()
|
|
231
|
+
var resumed = false
|
|
232
|
+
let finish: (Bool) -> Void = { value in
|
|
233
|
+
resumeLock.lock()
|
|
234
|
+
defer { resumeLock.unlock() }
|
|
235
|
+
guard !resumed else {
|
|
236
|
+
return
|
|
171
237
|
}
|
|
238
|
+
resumed = true
|
|
239
|
+
continuation.resume(returning: value)
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
DispatchQueue.main.async {
|
|
243
|
+
Task {
|
|
244
|
+
do {
|
|
245
|
+
let inner = try await callback(message).await()
|
|
246
|
+
let shouldShow = try await inner.await()
|
|
247
|
+
finish(shouldShow)
|
|
248
|
+
} catch {
|
|
249
|
+
finish(true)
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
|
|
255
|
+
finish(true)
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
private func flushPendingMessages() {
|
|
261
|
+
DispatchQueue.main.async {
|
|
262
|
+
let callback = self.synchronized { self.onMessage }
|
|
263
|
+
let queued = self.synchronized { () -> [PushMessage] in
|
|
264
|
+
let messages = self.pendingMessages
|
|
265
|
+
self.pendingMessages.removeAll()
|
|
266
|
+
return messages
|
|
172
267
|
}
|
|
173
|
-
|
|
174
|
-
|
|
268
|
+
guard let callback, !queued.isEmpty else {
|
|
269
|
+
return
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
for message in queued {
|
|
273
|
+
Task {
|
|
274
|
+
_ = await self.invokeOnMessage(callback, message: message)
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
private func shouldEmit(_ message: PushMessage) -> Bool {
|
|
281
|
+
let key = message.id ?? "\(message.title ?? "")|\(message.body ?? "")"
|
|
282
|
+
return synchronized {
|
|
283
|
+
let now = Date()
|
|
284
|
+
recentMessageIds = recentMessageIds.filter { now.timeIntervalSince($0.value) < 5 }
|
|
285
|
+
if let last = recentMessageIds[key], now.timeIntervalSince(last) < 2 {
|
|
175
286
|
return false
|
|
176
287
|
}
|
|
288
|
+
recentMessageIds[key] = now
|
|
289
|
+
return true
|
|
290
|
+
}
|
|
291
|
+
}
|
|
177
292
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
293
|
+
private func forwardWillPresent(
|
|
294
|
+
_ center: UNUserNotificationCenter,
|
|
295
|
+
notification: UNNotification,
|
|
296
|
+
ourOptions: UNNotificationPresentationOptions,
|
|
297
|
+
completionHandler: @escaping (UNNotificationPresentationOptions) -> Void
|
|
298
|
+
) {
|
|
299
|
+
let selector = #selector(
|
|
300
|
+
UNUserNotificationCenterDelegate.userNotificationCenter(_:willPresent:withCompletionHandler:)
|
|
301
|
+
)
|
|
302
|
+
guard let forwardingDelegate, forwardingDelegate.responds(to: selector) else {
|
|
303
|
+
completionHandler(ourOptions)
|
|
304
|
+
return
|
|
181
305
|
}
|
|
306
|
+
|
|
307
|
+
forwardingDelegate.userNotificationCenter?(
|
|
308
|
+
center,
|
|
309
|
+
willPresent: notification,
|
|
310
|
+
withCompletionHandler: { forwarded in
|
|
311
|
+
completionHandler(ourOptions.union(forwarded))
|
|
312
|
+
}
|
|
313
|
+
)
|
|
182
314
|
}
|
|
183
315
|
|
|
184
316
|
private static var foregroundPresentationOptions: UNNotificationPresentationOptions {
|
|
@@ -363,6 +495,25 @@ final class PushSignalCenter: NSObject, UNUserNotificationCenterDelegate {
|
|
|
363
495
|
)
|
|
364
496
|
}
|
|
365
497
|
|
|
498
|
+
private func swizzleNotificationCenterDelegateIfNeeded() {
|
|
499
|
+
guard !didSwizzleNotificationCenter else {
|
|
500
|
+
return
|
|
501
|
+
}
|
|
502
|
+
didSwizzleNotificationCenter = true
|
|
503
|
+
|
|
504
|
+
let target: AnyClass = UNUserNotificationCenter.self
|
|
505
|
+
let original = #selector(setter: UNUserNotificationCenter.delegate)
|
|
506
|
+
let replacement = #selector(UNUserNotificationCenter.pushSignal_setDelegate(_:))
|
|
507
|
+
|
|
508
|
+
guard let originalMethod = class_getInstanceMethod(target, original),
|
|
509
|
+
let replacementMethod = class_getInstanceMethod(target, replacement)
|
|
510
|
+
else {
|
|
511
|
+
return
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
method_exchangeImplementations(originalMethod, replacementMethod)
|
|
515
|
+
}
|
|
516
|
+
|
|
366
517
|
private func swizzle(target: AnyClass, original: Selector, replacement: Selector, source: AnyClass) {
|
|
367
518
|
guard let replacementMethod = class_getInstanceMethod(source, replacement) else {
|
|
368
519
|
return
|
|
@@ -423,3 +574,15 @@ private final class PushSignalAppDelegateHook: NSObject {
|
|
|
423
574
|
unsafeBitCast(method_getImplementation(method), to: Fn.self)(self, selector, application, error as NSError)
|
|
424
575
|
}
|
|
425
576
|
}
|
|
577
|
+
|
|
578
|
+
extension UNUserNotificationCenter {
|
|
579
|
+
@objc func pushSignal_setDelegate(_ delegate: UNUserNotificationCenterDelegate?) {
|
|
580
|
+
if let delegate, delegate is PushSignalCenter {
|
|
581
|
+
pushSignal_setDelegate(delegate)
|
|
582
|
+
return
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
PushSignalCenter.shared.rememberForwardingDelegate(delegate)
|
|
586
|
+
pushSignal_setDelegate(PushSignalCenter.shared)
|
|
587
|
+
}
|
|
588
|
+
}
|
|
@@ -10,12 +10,27 @@ NSDictionary *PushSignalCopyLaunchOptions(void) {
|
|
|
10
10
|
@implementation PushSignalLaunchStore
|
|
11
11
|
|
|
12
12
|
+ (void)load {
|
|
13
|
+
[[NSNotificationCenter defaultCenter]
|
|
14
|
+
addObserverForName:UIApplicationWillFinishLaunchingNotification
|
|
15
|
+
object:nil
|
|
16
|
+
queue:nil
|
|
17
|
+
usingBlock:^(NSNotification *notification) {
|
|
18
|
+
Class center = NSClassFromString(@"PushSignalCenter");
|
|
19
|
+
if ([center respondsToSelector:@selector(installEarly)]) {
|
|
20
|
+
[center installEarly];
|
|
21
|
+
}
|
|
22
|
+
}];
|
|
23
|
+
|
|
13
24
|
[[NSNotificationCenter defaultCenter]
|
|
14
25
|
addObserverForName:UIApplicationDidFinishLaunchingNotification
|
|
15
26
|
object:nil
|
|
16
27
|
queue:nil
|
|
17
28
|
usingBlock:^(NSNotification *notification) {
|
|
18
29
|
sLaunchOptions = [notification.userInfo copy];
|
|
30
|
+
Class center = NSClassFromString(@"PushSignalCenter");
|
|
31
|
+
if ([center respondsToSelector:@selector(bootstrapWithLaunchOptions:)]) {
|
|
32
|
+
[center bootstrapWithLaunchOptions:sLaunchOptions];
|
|
33
|
+
}
|
|
19
34
|
}];
|
|
20
35
|
}
|
|
21
36
|
|
|
@@ -11,7 +11,8 @@ function bindNativeCallbacks() {
|
|
|
11
11
|
}
|
|
12
12
|
nativeCallbacksBound = true;
|
|
13
13
|
PushSignalHybridObject.setOnMessage(async message => {
|
|
14
|
-
const
|
|
14
|
+
const listeners = [...messageListeners];
|
|
15
|
+
const results = await Promise.all(listeners.map(async listener => {
|
|
15
16
|
try {
|
|
16
17
|
return await listener(message);
|
|
17
18
|
} catch {
|
|
@@ -44,4 +45,5 @@ export function onNotificationPress(listener) {
|
|
|
44
45
|
pressListeners.delete(listener);
|
|
45
46
|
};
|
|
46
47
|
}
|
|
48
|
+
bindNativeCallbacks();
|
|
47
49
|
//# sourceMappingURL=pushSignal.native.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["NitroModules","PushSignalHybridObject","createHybridObject","messageListeners","Set","pressListeners","nativeCallbacksBound","bindNativeCallbacks","setOnMessage","message","results","Promise","all","map","listener","some","result","setOnNotificationPress","forEach","initialize","config","getCredentials","onMessage","add","delete","onNotificationPress"],"sourceRoot":"../../src","sources":["pushSignal.native.tsx"],"mappings":";;AAAA,SAASA,YAAY,QAAQ,4BAA4B;AASzD,MAAMC,sBAAsB,GAC1BD,YAAY,CAACE,kBAAkB,CAAa,YAAY,CAAC;AAE3D,MAAMC,gBAAgB,GAAG,IAAIC,GAAG,CAAoB,CAAC;AACrD,MAAMC,cAAc,GAAG,IAAID,GAAG,CAAiC,CAAC;AAChE,IAAIE,oBAAoB,GAAG,KAAK;AAEhC,SAASC,mBAAmBA,CAAA,EAAG;EAC7B,IAAID,oBAAoB,EAAE;IACxB;EACF;EAEAA,oBAAoB,GAAG,IAAI;EAE3BL,sBAAsB,CAACO,YAAY,CAAC,MAAOC,OAAO,IAAK;IACrD,MAAMC,OAAO,GAAG,MAAMC,OAAO,CAACC,GAAG,CAC/
|
|
1
|
+
{"version":3,"names":["NitroModules","PushSignalHybridObject","createHybridObject","messageListeners","Set","pressListeners","nativeCallbacksBound","bindNativeCallbacks","setOnMessage","message","listeners","results","Promise","all","map","listener","some","result","setOnNotificationPress","forEach","initialize","config","getCredentials","onMessage","add","delete","onNotificationPress"],"sourceRoot":"../../src","sources":["pushSignal.native.tsx"],"mappings":";;AAAA,SAASA,YAAY,QAAQ,4BAA4B;AASzD,MAAMC,sBAAsB,GAC1BD,YAAY,CAACE,kBAAkB,CAAa,YAAY,CAAC;AAE3D,MAAMC,gBAAgB,GAAG,IAAIC,GAAG,CAAoB,CAAC;AACrD,MAAMC,cAAc,GAAG,IAAID,GAAG,CAAiC,CAAC;AAChE,IAAIE,oBAAoB,GAAG,KAAK;AAEhC,SAASC,mBAAmBA,CAAA,EAAG;EAC7B,IAAID,oBAAoB,EAAE;IACxB;EACF;EAEAA,oBAAoB,GAAG,IAAI;EAE3BL,sBAAsB,CAACO,YAAY,CAAC,MAAOC,OAAO,IAAK;IACrD,MAAMC,SAAS,GAAG,CAAC,GAAGP,gBAAgB,CAAC;IACvC,MAAMQ,OAAO,GAAG,MAAMC,OAAO,CAACC,GAAG,CAC/BH,SAAS,CAACI,GAAG,CAAC,MAAOC,QAAQ,IAAK;MAChC,IAAI;QACF,OAAO,MAAMA,QAAQ,CAACN,OAAO,CAAC;MAChC,CAAC,CAAC,MAAM;QACN,OAAO,KAAK;MACd;IACF,CAAC,CACH,CAAC;IAED,OAAOE,OAAO,CAACK,IAAI,CAAEC,MAAM,IAAKA,MAAM,KAAK,IAAI,CAAC;EAClD,CAAC,CAAC;EAEFhB,sBAAsB,CAACiB,sBAAsB,CAAET,OAAO,IAAK;IACzDJ,cAAc,CAACc,OAAO,CAAEJ,QAAQ,IAAKA,QAAQ,CAACN,OAAO,CAAC,CAAC;EACzD,CAAC,CAAC;AACJ;AAEA,OAAO,SAASW,UAAUA,CAACC,MAA6B,GAAG,CAAC,CAAC,EAAiB;EAC5E,OAAOpB,sBAAsB,CAACmB,UAAU,CAACC,MAAM,CAAC;AAClD;AAEA,OAAO,SAASC,cAAcA,CAAA,EAA6B;EACzD,OAAOrB,sBAAsB,CAACqB,cAAc,CAAC,CAAC;AAChD;AAEA,OAAO,SAASC,SAASA,CAACR,QAA2B,EAAc;EACjER,mBAAmB,CAAC,CAAC;EACrBJ,gBAAgB,CAACqB,GAAG,CAACT,QAAQ,CAAC;EAC9B,OAAO,MAAM;IACXZ,gBAAgB,CAACsB,MAAM,CAACV,QAAQ,CAAC;EACnC,CAAC;AACH;AAEA,OAAO,SAASW,mBAAmBA,CACjCX,QAAwC,EAC5B;EACZR,mBAAmB,CAAC,CAAC;EACrBF,cAAc,CAACmB,GAAG,CAACT,QAAQ,CAAC;EAC5B,OAAO,MAAM;IACXV,cAAc,CAACoB,MAAM,CAACV,QAAQ,CAAC;EACjC,CAAC;AACH;AAEAR,mBAAmB,CAAC,CAAC","ignoreList":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pushSignal.native.d.ts","sourceRoot":"","sources":["../../../src/pushSignal.native.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,qBAAqB,EACrB,iBAAiB,EACjB,eAAe,EACf,WAAW,EAEZ,MAAM,uBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"pushSignal.native.d.ts","sourceRoot":"","sources":["../../../src/pushSignal.native.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,qBAAqB,EACrB,iBAAiB,EACjB,eAAe,EACf,WAAW,EAEZ,MAAM,uBAAoB,CAAC;AAoC5B,wBAAgB,UAAU,CAAC,MAAM,GAAE,qBAA0B,GAAG,OAAO,CAAC,IAAI,CAAC,CAE5E;AAED,wBAAgB,cAAc,IAAI,OAAO,CAAC,eAAe,CAAC,CAEzD;AAED,wBAAgB,SAAS,CAAC,QAAQ,EAAE,iBAAiB,GAAG,MAAM,IAAI,CAMjE;AAED,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,IAAI,GACvC,MAAM,IAAI,CAMZ"}
|
package/package.json
CHANGED
|
@@ -22,8 +22,9 @@ function bindNativeCallbacks() {
|
|
|
22
22
|
nativeCallbacksBound = true;
|
|
23
23
|
|
|
24
24
|
PushSignalHybridObject.setOnMessage(async (message) => {
|
|
25
|
+
const listeners = [...messageListeners];
|
|
25
26
|
const results = await Promise.all(
|
|
26
|
-
|
|
27
|
+
listeners.map(async (listener) => {
|
|
27
28
|
try {
|
|
28
29
|
return await listener(message);
|
|
29
30
|
} catch {
|
|
@@ -65,3 +66,5 @@ export function onNotificationPress(
|
|
|
65
66
|
pressListeners.delete(listener);
|
|
66
67
|
};
|
|
67
68
|
}
|
|
69
|
+
|
|
70
|
+
bindNativeCallbacks();
|