infobip-mobile-messaging-react-native-plugin 14.7.0 → 14.8.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/{infobip-mobile-messaging-react-native-plugin-14.6.1.tgz → infobip-mobile-messaging-react-native-plugin-14.8.2.tgz} +0 -0
- package/infobip-mobile-messaging-react-native-plugin.podspec +1 -1
- package/ios/MobileMessagingPlugin/RNMMChat.swift +32 -10
- package/ios/MobileMessagingPlugin/RNMMChatViewManager.swift +3 -1
- package/ios/MobileMessagingPlugin/RNMobileMessaging.swift +14 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@ The document describes library integration steps for your React Native project.
|
|
|
12
12
|
## Requirements
|
|
13
13
|
- node (v20.16.0 or higher)
|
|
14
14
|
- ruby (2.7.8 or higher; the Example app uses 3.3.5)
|
|
15
|
-
- React Native (v0.
|
|
15
|
+
- React Native (v0.84.0)
|
|
16
16
|
|
|
17
17
|
For iOS project:
|
|
18
18
|
- Xcode and Command Line Tools (16.x or newer, tested with 26.0.1)
|
|
Binary file
|
|
@@ -13,9 +13,15 @@ import MobileMessaging
|
|
|
13
13
|
class RNMMChat: NSObject {
|
|
14
14
|
private var willUseJWT = false
|
|
15
15
|
private var willUseChatExceptionHandler = false
|
|
16
|
-
private var jwtRequestQueue: [
|
|
16
|
+
private var jwtRequestQueue: [JWTRequest] = []
|
|
17
17
|
private let jwtQueueLock = NSLock()
|
|
18
18
|
|
|
19
|
+
private final class JWTRequest {
|
|
20
|
+
var completed = false
|
|
21
|
+
let onResult: (String?) -> Void
|
|
22
|
+
init(_ onResult: @escaping (String?) -> Void) { self.onResult = onResult }
|
|
23
|
+
}
|
|
24
|
+
|
|
19
25
|
@objc(showChat:)
|
|
20
26
|
func showChat(presentingOptions: NSDictionary) {
|
|
21
27
|
MobileMessaging.inAppChat?.delegate = self
|
|
@@ -161,22 +167,26 @@ class RNMMChat: NSObject {
|
|
|
161
167
|
@objc(setChatJwtProvider)
|
|
162
168
|
func setChatJwtProvider() {
|
|
163
169
|
willUseJWT = true
|
|
170
|
+
// We cannot rely on 'showChat' for setting the delegate as we have several presentation modes - any async provider/handler request sets the delegate to ensure proper completions are triggered
|
|
171
|
+
MobileMessaging.inAppChat?.delegate = self
|
|
164
172
|
}
|
|
165
173
|
|
|
166
174
|
@objc(setChatExceptionHandler:)
|
|
167
175
|
func setChatExceptionHandler(isHandlerPresent: NSNumber) {
|
|
168
176
|
// NSNumber due to how RN bridge wraps JavaScript booleans
|
|
169
177
|
willUseChatExceptionHandler = isHandlerPresent.boolValue
|
|
178
|
+
MobileMessaging.inAppChat?.delegate = self
|
|
170
179
|
}
|
|
171
180
|
|
|
172
181
|
@objc(setChatJwt:)
|
|
173
182
|
func setChatJwt(jwt: String?) {
|
|
174
183
|
jwtQueueLock.lock()
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
}
|
|
179
|
-
|
|
184
|
+
defer { jwtQueueLock.unlock() }
|
|
185
|
+
guard let request = jwtRequestQueue.first(where: { !$0.completed }) else { return }
|
|
186
|
+
request.completed = true
|
|
187
|
+
jwtRequestQueue.removeAll(where: { $0 === request })
|
|
188
|
+
// Settled inside the lock so a concurrent getJWT cleanup observes completed == true and jwtResult is set before getJWT returns.
|
|
189
|
+
request.onResult(jwt)
|
|
180
190
|
}
|
|
181
191
|
|
|
182
192
|
@objc(restartConnection)
|
|
@@ -201,15 +211,27 @@ extension RNMMChat: MMInAppChatDelegate {
|
|
|
201
211
|
guard willUseJWT else { return nil }
|
|
202
212
|
var jwtResult: String?
|
|
203
213
|
let semaphore = DispatchSemaphore(value: 0)
|
|
204
|
-
|
|
205
|
-
jwtQueueLock.lock()
|
|
206
|
-
jwtRequestQueue.append { jwt in
|
|
214
|
+
let request = JWTRequest { jwt in
|
|
207
215
|
jwtResult = jwt
|
|
208
216
|
semaphore.signal()
|
|
209
217
|
}
|
|
218
|
+
|
|
219
|
+
jwtQueueLock.lock()
|
|
220
|
+
jwtRequestQueue.append(request)
|
|
210
221
|
jwtQueueLock.unlock()
|
|
211
|
-
|
|
222
|
+
|
|
223
|
+
ReactNativeMobileMessaging.shared?.sendDirectEvent(withName: EventName.inAppChat_jwtRequested, body: nil)
|
|
212
224
|
_ = semaphore.wait(timeout: .now() + 45)
|
|
225
|
+
|
|
226
|
+
// Remove this request by identity (not position) so a setChatJwt that fires between the wait timeout and the lock cannot cause us to evict a different in-flight request.
|
|
227
|
+
jwtQueueLock.lock()
|
|
228
|
+
if !request.completed {
|
|
229
|
+
request.completed = true
|
|
230
|
+
if let idx = jwtRequestQueue.firstIndex(where: { $0 === request }) {
|
|
231
|
+
jwtRequestQueue.remove(at: idx)
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
jwtQueueLock.unlock()
|
|
213
235
|
return jwtResult
|
|
214
236
|
}
|
|
215
237
|
|
|
@@ -37,7 +37,9 @@ class RNMMChatViewManager: RCTViewManager {
|
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
override func didMoveToWindow() {
|
|
40
|
-
|
|
40
|
+
if window != nil { // this could be triggered in an improper manner from RN side, so we confirm UI is in a proper state
|
|
41
|
+
embedViewController()
|
|
42
|
+
}
|
|
41
43
|
super.didMoveToWindow()
|
|
42
44
|
}
|
|
43
45
|
|
|
@@ -64,6 +64,20 @@ class ReactNativeMobileMessaging: RCTEventEmitter {
|
|
|
64
64
|
}
|
|
65
65
|
super.sendEvent(withName: name, body: body)
|
|
66
66
|
}
|
|
67
|
+
|
|
68
|
+
func sendDirectEvent(withName name: String!, body: Any!) {
|
|
69
|
+
guard let _eventsManager = eventsManager, _eventsManager.hasEventListeners == true else {
|
|
70
|
+
// JS listener persists on the mobileMessaging singleton but RCTEventEmitter's _listenerCount may be zero during a React Navigation transition (reproducible with custom chat navigations and JWT async callback/authentication flow). Bypass that guard by invoking RCTDeviceEventEmitter directly via the public callableJSModules API (bridgeless-safe; the same path super.sendEvent uses internally).
|
|
71
|
+
MMLogDebug("[RNMobileMessaging] sendDirectEvent: invoking RCTDeviceEventEmitter directly")
|
|
72
|
+
self.callableJSModules?.invokeModule(
|
|
73
|
+
"RCTDeviceEventEmitter",
|
|
74
|
+
method: "emit",
|
|
75
|
+
withArgs: [name!, body ?? NSNull()]
|
|
76
|
+
)
|
|
77
|
+
return
|
|
78
|
+
}
|
|
79
|
+
super.sendEvent(withName: name, body: body)
|
|
80
|
+
}
|
|
67
81
|
|
|
68
82
|
@objc
|
|
69
83
|
override static func requiresMainQueueSetup() -> Bool {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "infobip-mobile-messaging-react-native-plugin",
|
|
3
3
|
"title": "Infobip Mobile Messaging React Native Plugin",
|
|
4
|
-
"version": "14.
|
|
4
|
+
"version": "14.8.3",
|
|
5
5
|
"description": "Infobip Mobile Messaging React Native Plugin",
|
|
6
6
|
"main": "./src/index.js",
|
|
7
7
|
"scripts": {
|