infobip-mobile-messaging-react-native-plugin 14.2.0-rc → 14.4.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/android/build.gradle +2 -2
- package/android/src/main/java/org/infobip/reactlibrary/mobilemessaging/CacheManager.java +3 -3
- package/android/src/main/java/org/infobip/reactlibrary/mobilemessaging/Configuration.java +3 -63
- package/android/src/main/java/org/infobip/reactlibrary/mobilemessaging/PermissionsRequestManager.java +1 -2
- package/android/src/main/java/org/infobip/reactlibrary/mobilemessaging/RNMMChatService.kt +35 -33
- package/android/src/main/java/org/infobip/reactlibrary/mobilemessaging/RNMMChatView.kt +6 -6
- package/android/src/main/java/org/infobip/reactlibrary/mobilemessaging/RNMMLogWriter.kt +91 -0
- package/android/src/main/java/org/infobip/reactlibrary/mobilemessaging/RNMMLogger.kt +82 -0
- package/android/src/main/java/org/infobip/reactlibrary/mobilemessaging/RNMMWebRTCUIService.kt +61 -0
- package/android/src/main/java/org/infobip/reactlibrary/mobilemessaging/ReactNativeEvent.java +5 -5
- package/android/src/main/java/org/infobip/reactlibrary/mobilemessaging/ReactNativeMobileMessagingPackage.kt +4 -4
- package/android/src/main/java/org/infobip/reactlibrary/mobilemessaging/ReactNativeMobileMessagingService.kt +77 -64
- package/android/src/main/java/org/infobip/reactlibrary/mobilemessaging/Utils.java +1 -1
- package/android/src/newarchitecture/java/org/infobip/reactlibrary/mobilemessaging/MobileMessagingModule.kt +27 -27
- package/android/src/newarchitecture/java/org/infobip/reactlibrary/mobilemessaging/RNMMChatModule.kt +26 -16
- package/android/src/newarchitecture/java/org/infobip/reactlibrary/mobilemessaging/RNMMChatViewManager.kt +5 -5
- package/android/src/newarchitecture/java/org/infobip/reactlibrary/mobilemessaging/RNMMWebRTCUIModule.kt +3 -3
- package/android/src/oldarchitecture/java/org/infobip/reactlibrary/mobilemessaging/MobileMessagingModule.kt +27 -27
- package/android/src/oldarchitecture/java/org/infobip/reactlibrary/mobilemessaging/RNMMChatModule.kt +27 -15
- package/android/src/oldarchitecture/java/org/infobip/reactlibrary/mobilemessaging/RNMMChatViewManager.kt +6 -6
- package/android/src/oldarchitecture/java/org/infobip/reactlibrary/mobilemessaging/RNMMWebRTCUIModule.kt +3 -3
- package/infobip-mobile-messaging-react-native-plugin-14.3.0.tgz +0 -0
- package/infobip-mobile-messaging-react-native-plugin.podspec +1 -1
- package/ios/MobileMessagingPlugin/RNMMChat.swift +26 -3
- package/ios/MobileMessagingPlugin/RNMMChatBridge.m +2 -0
- package/ios/MobileMessagingPlugin/RNMMChatCustomization.swift +39 -102
- package/ios/MobileMessagingPlugin/RNMMLogger.swift +53 -0
- package/ios/MobileMessagingPlugin/RNMobileMessaging.swift +16 -7
- package/ios/MobileMessagingPlugin/RNMobileMessagingConfiguration.swift +4 -1
- package/ios/MobileMessagingPlugin/RNMobileMessagingEventsManager.swift +5 -3
- package/ios/MobileMessagingPlugin/RNMobileMessagingUtils.swift +1 -0
- package/ios/ReactNativeMobileMessaging.xcodeproj/project.pbxproj +4 -0
- package/package.json +4 -4
- package/release.sh +1 -1
- package/src/index.d.ts +160 -182
- package/src/index.js +46 -6
- package/src/specs/NativeRNMMChat.ts +2 -0
- package/infobip-mobile-messaging-react-native-plugin-14.1.4.tgz +0 -0
package/android/build.gradle
CHANGED
|
@@ -66,7 +66,7 @@ repositories {
|
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
dependencies {
|
|
69
|
-
def mmVersion = '14.
|
|
69
|
+
def mmVersion = '14.11.0'
|
|
70
70
|
implementation "org.jetbrains.kotlin:kotlin-stdlib:2.1.20"
|
|
71
71
|
compileOnly "com.facebook.react:react-android"
|
|
72
72
|
implementation "androidx.annotation:annotation:1.9.1"
|
|
@@ -100,4 +100,4 @@ dependencies {
|
|
|
100
100
|
if (!overrideFirebaseVersion.empty) {
|
|
101
101
|
implementation "com.google.firebase:firebase-messaging:$overrideFirebaseVersion"
|
|
102
102
|
}
|
|
103
|
-
}
|
|
103
|
+
}
|
|
@@ -50,7 +50,7 @@ class CacheManager {
|
|
|
50
50
|
|
|
51
51
|
static void saveEvent(Context context, String event, JSONObject object, String actionId, String actionInputText) {
|
|
52
52
|
if (context == null) {
|
|
53
|
-
|
|
53
|
+
RNMMLogger.e(Utils.TAG, "context is null, can't cache event " + event);
|
|
54
54
|
return;
|
|
55
55
|
}
|
|
56
56
|
String serialized = serializer.serialize(new Event(event, object, actionId, actionInputText));
|
|
@@ -59,7 +59,7 @@ class CacheManager {
|
|
|
59
59
|
|
|
60
60
|
static void saveEvent(Context context, String event, int unreadMessagesCounter) {
|
|
61
61
|
if (context == null) {
|
|
62
|
-
|
|
62
|
+
RNMMLogger.e(Utils.TAG, "context is null, can't cache event " + event);
|
|
63
63
|
return;
|
|
64
64
|
}
|
|
65
65
|
//int `unreadMessagesCounter` isn't a JSONObject, so it'll go as a second argument
|
|
@@ -69,7 +69,7 @@ class CacheManager {
|
|
|
69
69
|
|
|
70
70
|
static Event[] loadEvents(Context context, String eventType) {
|
|
71
71
|
if (context == null) {
|
|
72
|
-
|
|
72
|
+
RNMMLogger.e(Utils.TAG, "context is null, can't load cached events " + eventType);
|
|
73
73
|
return new Event[0];
|
|
74
74
|
}
|
|
75
75
|
Set<String> serialized = getStringSet(context, EVENTS_KEY);
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
package org.infobip.reactlibrary.mobilemessaging;
|
|
10
10
|
|
|
11
11
|
import androidx.annotation.NonNull;
|
|
12
|
+
import androidx.annotation.Nullable;
|
|
12
13
|
|
|
13
14
|
import com.google.firebase.FirebaseOptions;
|
|
14
15
|
|
|
@@ -52,53 +53,6 @@ public class Configuration {
|
|
|
52
53
|
List<Action> actions;
|
|
53
54
|
}
|
|
54
55
|
|
|
55
|
-
class InAppChatCustomization {
|
|
56
|
-
//common
|
|
57
|
-
String widgetTheme;
|
|
58
|
-
String toolbarTitle;
|
|
59
|
-
String toolbarTitleColor;
|
|
60
|
-
String toolbarBackgroundColor;
|
|
61
|
-
String chatBackgroundColor;
|
|
62
|
-
String noConnectionAlertTextColor;
|
|
63
|
-
String noConnectionAlertBackgroundColor;
|
|
64
|
-
String chatInputPlaceholderTextColor;
|
|
65
|
-
String chatInputCursorColor;
|
|
66
|
-
String chatInputBackgroundColor;
|
|
67
|
-
String sendButtonIconUri;
|
|
68
|
-
String attachmentButtonIconUri;
|
|
69
|
-
boolean chatInputSeparatorVisible;
|
|
70
|
-
//android only
|
|
71
|
-
//status bar properties
|
|
72
|
-
boolean statusBarColorLight;
|
|
73
|
-
String statusBarBackgroundColor;
|
|
74
|
-
//toolbar properties
|
|
75
|
-
String navigationIconUri;
|
|
76
|
-
String navigationIconTint;
|
|
77
|
-
String subtitleText;
|
|
78
|
-
String subtitleTextColor;
|
|
79
|
-
String subtitleTextAppearanceRes;
|
|
80
|
-
boolean subtitleCentered;
|
|
81
|
-
String titleTextAppearanceRes;
|
|
82
|
-
boolean titleCentered;
|
|
83
|
-
String menuItemsIconTint;
|
|
84
|
-
String menuItemSaveAttachmentIcon;
|
|
85
|
-
//chat properties
|
|
86
|
-
String progressBarColor;
|
|
87
|
-
String networkConnectionErrorTextAppearanceRes;
|
|
88
|
-
String networkConnectionErrorText;
|
|
89
|
-
//chat input properties
|
|
90
|
-
String inputTextColor;
|
|
91
|
-
String inputAttachmentIconTint;
|
|
92
|
-
String inputAttachmentBackgroundColor;
|
|
93
|
-
String inputAttachmentBackgroundDrawable;
|
|
94
|
-
String inputSendIconTint;
|
|
95
|
-
String inputSendBackgroundColor;
|
|
96
|
-
String inputSendBackgroundDrawable;
|
|
97
|
-
String inputSeparatorLineColor;
|
|
98
|
-
String inputHintText;
|
|
99
|
-
String inputTextAppearance;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
56
|
class WebRTCUI {
|
|
103
57
|
String configurationId;
|
|
104
58
|
}
|
|
@@ -109,13 +63,13 @@ public class Configuration {
|
|
|
109
63
|
boolean fullFeaturedInAppsEnabled;
|
|
110
64
|
Map<String, ?> messageStorage;
|
|
111
65
|
boolean defaultMessageStorage;
|
|
112
|
-
boolean
|
|
66
|
+
boolean logging;
|
|
113
67
|
String reactNativePluginVersion = "unknown";
|
|
114
68
|
PrivacySettings privacySettings = new PrivacySettings();
|
|
115
69
|
List<Category> notificationCategories = new ArrayList<Category>();
|
|
116
70
|
WebRTCUI webRTCUI;
|
|
117
|
-
InAppChatCustomization inAppChatCustomization;
|
|
118
71
|
String userDataJwt;
|
|
72
|
+
@Nullable String backendBaseURL;
|
|
119
73
|
|
|
120
74
|
@NonNull
|
|
121
75
|
static Configuration resolveConfiguration(JSONObject args) throws JSONException {
|
|
@@ -130,18 +84,4 @@ public class Configuration {
|
|
|
130
84
|
|
|
131
85
|
return config;
|
|
132
86
|
}
|
|
133
|
-
|
|
134
|
-
@NonNull
|
|
135
|
-
static InAppChatCustomization resolveChatSettings(JSONObject args) throws JSONException {
|
|
136
|
-
if (args == null) {
|
|
137
|
-
throw new IllegalArgumentException("Cannot resolve configuration from arguments");
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
InAppChatCustomization config = new JsonSerializer().deserialize(args.toString(), InAppChatCustomization.class);
|
|
141
|
-
if (config == null) {
|
|
142
|
-
throw new IllegalArgumentException("Configuration is invalid");
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
return config;
|
|
146
|
-
}
|
|
147
87
|
}
|
|
@@ -22,7 +22,6 @@ import com.facebook.react.modules.core.PermissionAwareActivity;
|
|
|
22
22
|
import com.facebook.react.modules.core.PermissionListener;
|
|
23
23
|
|
|
24
24
|
import org.infobip.mobile.messaging.resources.R;
|
|
25
|
-
import org.infobip.mobile.messaging.logging.MobileMessagingLogger;
|
|
26
25
|
import org.infobip.mobile.messaging.permissions.PermissionsHelper;
|
|
27
26
|
|
|
28
27
|
import java.util.Set;
|
|
@@ -155,7 +154,7 @@ public class PermissionsRequestManager {
|
|
|
155
154
|
}
|
|
156
155
|
|
|
157
156
|
protected void openSettings(Activity activity) {
|
|
158
|
-
|
|
157
|
+
RNMMLogger.d(Utils.TAG, "Will open application settings activity");
|
|
159
158
|
Intent intent = new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
|
|
160
159
|
Uri uri = Uri.fromParts("package", activity.getPackageName(), null);
|
|
161
160
|
intent.setData(uri);
|
|
@@ -8,7 +8,6 @@
|
|
|
8
8
|
|
|
9
9
|
package org.infobip.reactlibrary.mobilemessaging
|
|
10
10
|
|
|
11
|
-
import android.annotation.SuppressLint
|
|
12
11
|
import android.app.Activity
|
|
13
12
|
import android.content.BroadcastReceiver
|
|
14
13
|
import android.content.Context
|
|
@@ -82,7 +81,7 @@ class RNMMChatService(
|
|
|
82
81
|
override fun onReceive(context: Context, intent: Intent) {
|
|
83
82
|
val event = broadcastEventMap[intent.action]
|
|
84
83
|
if (event == null) {
|
|
85
|
-
|
|
84
|
+
RNMMLogger.w(TAG, "Cannot process event for broadcast: ${intent.action}")
|
|
86
85
|
return
|
|
87
86
|
}
|
|
88
87
|
|
|
@@ -135,6 +134,12 @@ class RNMMChatService(
|
|
|
135
134
|
}
|
|
136
135
|
}
|
|
137
136
|
|
|
137
|
+
fun isChatAvailable(onSuccess: Callback) {
|
|
138
|
+
runCatchingExceptions("isChatAvailable()") {
|
|
139
|
+
onSuccess.invoke(inAppChat.isChatAvailable())
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
138
143
|
fun resetMessageCounter() {
|
|
139
144
|
runCatchingExceptions("resetMessageCounter()") {
|
|
140
145
|
inAppChat.resetMessageCounter()
|
|
@@ -174,7 +179,7 @@ class RNMMChatService(
|
|
|
174
179
|
errorHandler = { t ->
|
|
175
180
|
onError.invoke(Utils.callbackError(t.message, null))
|
|
176
181
|
}
|
|
177
|
-
|
|
182
|
+
)
|
|
178
183
|
}
|
|
179
184
|
|
|
180
185
|
fun setWidgetTheme(widgetTheme: String?) {
|
|
@@ -184,7 +189,6 @@ class RNMMChatService(
|
|
|
184
189
|
}
|
|
185
190
|
|
|
186
191
|
private val reactNativeDrawableLoader = object : PluginChatCustomization.DrawableLoader {
|
|
187
|
-
@SuppressLint("LongLogTag")
|
|
188
192
|
override fun loadDrawable(context: Context, drawableSrc: String?): Drawable? {
|
|
189
193
|
if (drawableSrc.isNullOrBlank()) return null
|
|
190
194
|
return try {
|
|
@@ -192,7 +196,7 @@ class RNMMChatService(
|
|
|
192
196
|
BitmapDrawable(context.resources, drawableStream)
|
|
193
197
|
}
|
|
194
198
|
} catch (e: IOException) {
|
|
195
|
-
|
|
199
|
+
RNMMLogger.e("PluginChatCustomization.DrawableLoader", "Failed to load image $drawableSrc", e)
|
|
196
200
|
null
|
|
197
201
|
}
|
|
198
202
|
}
|
|
@@ -227,7 +231,7 @@ class RNMMChatService(
|
|
|
227
231
|
private fun sendRequestEvent() {
|
|
228
232
|
reactContext
|
|
229
233
|
?.let { ReactNativeEvent.send(EVENT_INAPPCHAT_JWT_REQUESTED, it)}
|
|
230
|
-
?:
|
|
234
|
+
?: RNMMLogger.e(TAG, "React context is null, cannot send request for JWT.")
|
|
231
235
|
}
|
|
232
236
|
|
|
233
237
|
fun requestJwt(callback: JwtProvider.JwtCallback) {
|
|
@@ -244,11 +248,11 @@ class RNMMChatService(
|
|
|
244
248
|
updateAwaitingState()
|
|
245
249
|
}
|
|
246
250
|
reactContext?.runOnUiQueueThread(runnable) ?: run {
|
|
247
|
-
|
|
251
|
+
RNMMLogger.w(TAG, "React context is null, cannot resume with JWT value on UI thread.")
|
|
248
252
|
runnable.run()
|
|
249
253
|
}
|
|
250
254
|
} catch (e: Exception) {
|
|
251
|
-
|
|
255
|
+
RNMMLogger.e(TAG, "Could not resume with JWT value $newJwt", e)
|
|
252
256
|
}
|
|
253
257
|
}
|
|
254
258
|
|
|
@@ -259,11 +263,11 @@ class RNMMChatService(
|
|
|
259
263
|
updateAwaitingState()
|
|
260
264
|
}
|
|
261
265
|
reactContext?.runOnUiQueueThread(runnable) ?: run {
|
|
262
|
-
|
|
266
|
+
RNMMLogger.w(TAG, "React context is null, cannot resume with JWT error on UI thread.")
|
|
263
267
|
runnable.run()
|
|
264
268
|
}
|
|
265
269
|
} catch (e: Exception) {
|
|
266
|
-
|
|
270
|
+
RNMMLogger.e(TAG, "Could not resume with JWT error ${throwable.message}", e)
|
|
267
271
|
}
|
|
268
272
|
}
|
|
269
273
|
|
|
@@ -320,42 +324,46 @@ class RNMMChatService(
|
|
|
320
324
|
override fun handleError(@NonNull exception: InAppChatException): Boolean {
|
|
321
325
|
reactContext
|
|
322
326
|
?.let { ReactNativeEvent.send(EVENT_INAPPCHAT_EXCEPTION_RECEIVED, it, exception.toJSON())}
|
|
323
|
-
?:
|
|
327
|
+
?: RNMMLogger.e(Utils.TAG, "React context is null, cannot propagate chat exception.")
|
|
324
328
|
return true
|
|
325
329
|
}
|
|
326
330
|
}
|
|
327
331
|
}
|
|
332
|
+
|
|
333
|
+
fun setChatDomain(domain: String?) {
|
|
334
|
+
runCatchingExceptions("setChatDomain()", arrayOf(domain)) {
|
|
335
|
+
inAppChat.setDomain(domain)
|
|
336
|
+
}
|
|
337
|
+
}
|
|
328
338
|
//endregion
|
|
329
339
|
|
|
330
340
|
//region ActivityEventListener
|
|
331
|
-
override fun onActivityResult(
|
|
332
|
-
activity: Activity,
|
|
333
|
-
requestCode: Int,
|
|
334
|
-
resultCode: Int,
|
|
335
|
-
data: Intent?
|
|
336
|
-
) {
|
|
341
|
+
override fun onActivityResult(activity: Activity?, requestCode: Int, resultCode: Int, data: Intent?) {
|
|
337
342
|
val fragmentActivity = Utils.getFragmentActivity(reactContext) ?: return
|
|
338
343
|
val fragment = fragmentActivity.supportFragmentManager.findFragmentByTag(Utils.RN_IN_APP_CHAT_FRAGMENT_TAG)
|
|
339
344
|
if (fragment == null) {
|
|
340
|
-
|
|
345
|
+
RNMMLogger.w(TAG, "Can't find ${Utils.RN_IN_APP_CHAT_FRAGMENT_TAG} to provide onActivityResult")
|
|
341
346
|
return
|
|
342
347
|
}
|
|
343
348
|
fragment.onActivityResult(requestCode and 0xffff, resultCode, data)
|
|
344
349
|
}
|
|
345
350
|
|
|
351
|
+
override fun onNewIntent(intent: Intent?) {
|
|
352
|
+
// Activity `onNewIntent` - no-op
|
|
353
|
+
}
|
|
346
354
|
//endregion
|
|
347
355
|
|
|
348
356
|
//region LifecycleEventListener
|
|
349
357
|
override fun onHostResume() {
|
|
350
|
-
|
|
358
|
+
RNMMLogger.d(TAG, "onHostResume()")
|
|
351
359
|
}
|
|
352
360
|
|
|
353
361
|
override fun onHostPause() {
|
|
354
|
-
|
|
362
|
+
RNMMLogger.d(TAG, "onHostPause()")
|
|
355
363
|
}
|
|
356
364
|
|
|
357
365
|
override fun onHostDestroy() {
|
|
358
|
-
|
|
366
|
+
RNMMLogger.d(TAG, "onHostDestroy()")
|
|
359
367
|
reactContext.removeActivityEventListener(this)
|
|
360
368
|
reactContext.removeLifecycleEventListener(this)
|
|
361
369
|
}
|
|
@@ -364,17 +372,13 @@ class RNMMChatService(
|
|
|
364
372
|
//region Helpers
|
|
365
373
|
private fun runCatchingExceptions(functionName: String, args: Array<out Any?> = emptyArray(), errorHandler: ((Throwable) -> Unit)? = null, block: () -> Unit) {
|
|
366
374
|
val argsLog = if (args.isEmpty()) "" else " Arguments: ${args.joinToString()}"
|
|
367
|
-
|
|
375
|
+
RNMMLogger.d(TAG, "$functionName$argsLog")
|
|
368
376
|
try {
|
|
369
377
|
block()
|
|
370
378
|
} catch (throwable: Throwable) {
|
|
371
|
-
errorHandler?.invoke(throwable) ?:
|
|
379
|
+
errorHandler?.invoke(throwable) ?: RNMMLogger.e(TAG, "$functionName error: ${throwable.message}", throwable)
|
|
372
380
|
}
|
|
373
381
|
}
|
|
374
|
-
|
|
375
|
-
override fun onNewIntent(intent: Intent) {
|
|
376
|
-
TODO("Not yet implemented")
|
|
377
|
-
}
|
|
378
382
|
//endregion
|
|
379
383
|
}
|
|
380
384
|
|
|
@@ -386,13 +390,11 @@ class RNMMChatEventReceiver : ReactNativeBroadcastReceiver() {
|
|
|
386
390
|
|
|
387
391
|
override fun onReceive(context: Context?, intent: Intent?) {
|
|
388
392
|
if (InAppChatEvent.UNREAD_MESSAGES_COUNTER_UPDATED.key != intent?.action) {
|
|
389
|
-
|
|
393
|
+
RNMMLogger.w(TAG, "Cannot process event for broadcast: ${intent?.action}")
|
|
390
394
|
return
|
|
391
395
|
}
|
|
392
|
-
val unreadChatMessagesCounter = intent
|
|
393
|
-
|
|
394
|
-
emitOrCache(context, RNMMChatService.EVENT_INAPPCHAT_UNREAD_MESSAGES_COUNT_UPDATED, unreadChatMessagesCounter)
|
|
395
|
-
}
|
|
396
|
+
val unreadChatMessagesCounter = intent.getIntExtra(BroadcastParameter.EXTRA_UNREAD_CHAT_MESSAGES_COUNT, 0)
|
|
397
|
+
emitOrCache(context, RNMMChatService.EVENT_INAPPCHAT_UNREAD_MESSAGES_COUNT_UPDATED, unreadChatMessagesCounter)
|
|
396
398
|
}
|
|
397
399
|
|
|
398
400
|
private fun emitOrCache(context: Context?, eventType: String, unreadMessagesCounter: Int) {
|
|
@@ -406,7 +408,7 @@ class RNMMChatEventReceiver : ReactNativeBroadcastReceiver() {
|
|
|
406
408
|
} else if (context != null) {
|
|
407
409
|
CacheManager.saveEvent(context, eventType, unreadMessagesCounter)
|
|
408
410
|
} else {
|
|
409
|
-
|
|
411
|
+
RNMMLogger.e(TAG, "Both reactContext and androidContext are null, can't emit or cache event " + eventType)
|
|
410
412
|
}
|
|
411
413
|
}
|
|
412
414
|
}
|
|
@@ -66,7 +66,7 @@ class RNMMChatView @JvmOverloads constructor(
|
|
|
66
66
|
if (parent is ViewGroup) {
|
|
67
67
|
setupLayoutHack(parent)
|
|
68
68
|
} else {
|
|
69
|
-
|
|
69
|
+
RNMMLogger.e(TAG, "Parent is not ViewGroup, cannot show InAppChatFragment.")
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
val fragmentManager = fragmentActivity?.supportFragmentManager
|
|
@@ -75,7 +75,7 @@ class RNMMChatView @JvmOverloads constructor(
|
|
|
75
75
|
.replace(this.id, fragment, Utils.RN_IN_APP_CHAT_FRAGMENT_TAG)
|
|
76
76
|
.commitNow()
|
|
77
77
|
} else {
|
|
78
|
-
|
|
78
|
+
RNMMLogger.e(TAG, "FragmentManager is null, cannot add InAppChatFragment.")
|
|
79
79
|
}
|
|
80
80
|
}
|
|
81
81
|
}
|
|
@@ -91,7 +91,7 @@ class RNMMChatView @JvmOverloads constructor(
|
|
|
91
91
|
.commitNow()
|
|
92
92
|
cachedFragment = null
|
|
93
93
|
} else {
|
|
94
|
-
|
|
94
|
+
RNMMLogger.e(TAG, "InAppChatFragment or FragmentManager is null, cannot remove InAppChatFragment.")
|
|
95
95
|
}
|
|
96
96
|
}
|
|
97
97
|
}
|
|
@@ -102,7 +102,7 @@ class RNMMChatView @JvmOverloads constructor(
|
|
|
102
102
|
if (fragment != null) {
|
|
103
103
|
fragment.showThreadList()
|
|
104
104
|
} else {
|
|
105
|
-
|
|
105
|
+
RNMMLogger.e(TAG, "InAppChatFragment is null, cannot show threads list.")
|
|
106
106
|
}
|
|
107
107
|
}
|
|
108
108
|
}
|
|
@@ -133,11 +133,11 @@ class RNMMChatView @JvmOverloads constructor(
|
|
|
133
133
|
//region Helpers
|
|
134
134
|
private fun runCatchingExceptions(functionName: String, args: Array<out Any?> = emptyArray(), errorHandler: ((Throwable) -> Unit)? = null, block: () -> Unit) {
|
|
135
135
|
val argsLog = if (args.isEmpty()) "" else " Arguments: ${args.joinToString()}"
|
|
136
|
-
|
|
136
|
+
RNMMLogger.d(TAG, "$functionName$argsLog")
|
|
137
137
|
try {
|
|
138
138
|
block()
|
|
139
139
|
} catch (throwable: Throwable) {
|
|
140
|
-
errorHandler?.invoke(throwable) ?:
|
|
140
|
+
errorHandler?.invoke(throwable) ?: RNMMLogger.e(TAG, "$functionName error: ${throwable.message}", throwable)
|
|
141
141
|
}
|
|
142
142
|
}
|
|
143
143
|
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
//
|
|
2
|
+
// RNMMLogWriter.kt
|
|
3
|
+
// MobileMessagingReactNative
|
|
4
|
+
//
|
|
5
|
+
// Copyright (c) 2016-2025 Infobip Limited
|
|
6
|
+
// Licensed under the Apache License, Version 2.0
|
|
7
|
+
//
|
|
8
|
+
|
|
9
|
+
package org.infobip.reactlibrary.mobilemessaging
|
|
10
|
+
|
|
11
|
+
import android.util.Log
|
|
12
|
+
import com.facebook.react.bridge.ReactContext
|
|
13
|
+
import org.infobip.mobile.messaging.logging.Writer
|
|
14
|
+
import org.infobip.mobile.messaging.logging.Level
|
|
15
|
+
import org.infobip.mobile.messaging.logging.LogcatWriter
|
|
16
|
+
import org.infobip.reactlibrary.mobilemessaging.datamappers.ReactNativeJson
|
|
17
|
+
import org.json.JSONObject
|
|
18
|
+
import java.text.SimpleDateFormat
|
|
19
|
+
import java.util.Date
|
|
20
|
+
import java.util.Locale
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Custom log writer that proxies Android native SDK logs to React Native console
|
|
24
|
+
* Implements the Writer interface from MobileMessagingLogger
|
|
25
|
+
*/
|
|
26
|
+
class RNMMLogWriter(private val reactContext: ReactContext?) : Writer {
|
|
27
|
+
|
|
28
|
+
companion object {
|
|
29
|
+
private val dateFormat = SimpleDateFormat("HH:mm:ss.SSS", Locale.US)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
private val logcatWriter: LogcatWriter = LogcatWriter()
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Called by MobileMessagingLogger for each log entry
|
|
36
|
+
* Converts log level to prefix and emits event to React Native
|
|
37
|
+
*
|
|
38
|
+
* @param level Log level (VERBOSE, DEBUG, INFO, WARN, ERROR)
|
|
39
|
+
* @param tag Log tag (usually SDK component name)
|
|
40
|
+
* @param message Log message
|
|
41
|
+
* @param throwable Optional exception/throwable
|
|
42
|
+
*/
|
|
43
|
+
override fun write(level: Level, tag: String, message: String, throwable: Throwable?) {
|
|
44
|
+
write(level.name, tag, message, throwable)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Called by RNMMLogger for each log entry
|
|
49
|
+
* Converts log level to prefix and emits event to React Native
|
|
50
|
+
*
|
|
51
|
+
* @param level Log level (VERBOSE, DEBUG, INFO, WARN, ERROR)
|
|
52
|
+
* @param tag Log tag (usually SDK component name)
|
|
53
|
+
* @param message Log message
|
|
54
|
+
* @param throwable Optional exception/throwable
|
|
55
|
+
*/
|
|
56
|
+
fun write(level: String?, tag: String?, message: String?, throwable: Throwable?) {
|
|
57
|
+
if (message.isNullOrBlank())
|
|
58
|
+
return
|
|
59
|
+
|
|
60
|
+
if (reactContext == null) {
|
|
61
|
+
// Fallback to Logcat if message cannot be logged by RN console
|
|
62
|
+
runCatching {
|
|
63
|
+
logcatWriter.write(Level.valueOf(level ?: Level.DEBUG.name), tag, message, throwable)
|
|
64
|
+
}.onFailure {
|
|
65
|
+
logcatWriter.write(Level.DEBUG, tag, message, throwable)
|
|
66
|
+
}
|
|
67
|
+
return
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
val timestamp = dateFormat.format(Date())
|
|
71
|
+
val fullMessage = if (throwable != null) {
|
|
72
|
+
"$message\n${Log.getStackTraceString(throwable)}"
|
|
73
|
+
} else {
|
|
74
|
+
message
|
|
75
|
+
}
|
|
76
|
+
val tagLog = if(tag?.isNullOrBlank() == true) "" else " [$tag]"
|
|
77
|
+
val logcatStyleMessage = "$timestamp$tagLog: $fullMessage"
|
|
78
|
+
val prefixedMessage = when (level) {
|
|
79
|
+
Level.WARN.name -> "RNMMWARN: $logcatStyleMessage"
|
|
80
|
+
Level.ERROR.name -> "RNMMERROR: $logcatStyleMessage"
|
|
81
|
+
else -> logcatStyleMessage
|
|
82
|
+
}
|
|
83
|
+
val payload = JSONObject().apply {
|
|
84
|
+
put("message", prefixedMessage)
|
|
85
|
+
}
|
|
86
|
+
val payloadMap = ReactNativeJson.convertJsonToMap(payload)
|
|
87
|
+
ReactNativeEvent.send(ReactNativeMobileMessagingService.EVENT_PLATFORM_NATIVE_LOG_SENT, reactContext, payloadMap)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
//
|
|
2
|
+
// RNMMLogger.kt
|
|
3
|
+
// MobileMessagingReactNative
|
|
4
|
+
//
|
|
5
|
+
// Copyright (c) 2016-2025 Infobip Limited
|
|
6
|
+
// Licensed under the Apache License, Version 2.0
|
|
7
|
+
//
|
|
8
|
+
|
|
9
|
+
package org.infobip.reactlibrary.mobilemessaging
|
|
10
|
+
|
|
11
|
+
import org.infobip.mobile.messaging.logging.Level
|
|
12
|
+
import android.util.Log
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Centralized logging utility for React Native plugin code.
|
|
16
|
+
* Routes logs to EITHER React Native console OR Android Logcat (mutually exclusive).
|
|
17
|
+
*/
|
|
18
|
+
object RNMMLogger {
|
|
19
|
+
|
|
20
|
+
private var writer: RNMMLogWriter? = null
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Route logs to React Native console via RNMMLogWriter.
|
|
24
|
+
* When enabled, logs will NOT appear in Android Logcat.
|
|
25
|
+
*/
|
|
26
|
+
fun useReactNativeConsole(writer: RNMMLogWriter) {
|
|
27
|
+
this.writer = writer
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Route logs to Android Logcat (default behavior).
|
|
32
|
+
* When enabled, logs will NOT appear in React Native console.s
|
|
33
|
+
*/
|
|
34
|
+
fun useNativeLogcat() {
|
|
35
|
+
this.writer = null
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Log a VERBOSE message.
|
|
40
|
+
*/
|
|
41
|
+
@JvmStatic
|
|
42
|
+
@JvmOverloads
|
|
43
|
+
fun v(tag: String, message: String, throwable: Throwable? = null) {
|
|
44
|
+
writer?.write(Level.VERBOSE.name, tag, message, throwable) ?: Log.v(tag, message, throwable)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Log a DEBUG message.
|
|
49
|
+
*/
|
|
50
|
+
@JvmStatic
|
|
51
|
+
@JvmOverloads
|
|
52
|
+
fun d(tag: String, message: String, throwable: Throwable? = null) {
|
|
53
|
+
writer?.write(Level.DEBUG.name, tag, message, throwable) ?: Log.d(tag, message, throwable)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Log an INFO message.
|
|
58
|
+
*/
|
|
59
|
+
@JvmStatic
|
|
60
|
+
@JvmOverloads
|
|
61
|
+
fun i(tag: String, message: String, throwable: Throwable? = null) {
|
|
62
|
+
writer?.write(Level.INFO.name, tag, message, throwable) ?: Log.i(tag, message, throwable)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Log a WARN message.
|
|
67
|
+
*/
|
|
68
|
+
@JvmStatic
|
|
69
|
+
@JvmOverloads
|
|
70
|
+
fun w(tag: String, message: String, throwable: Throwable? = null) {
|
|
71
|
+
writer?.write(Level.WARN.name, tag, message, throwable) ?: Log.w(tag, message, throwable)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Log an ERROR message.
|
|
76
|
+
*/
|
|
77
|
+
@JvmStatic
|
|
78
|
+
@JvmOverloads
|
|
79
|
+
fun e(tag: String, message: String, throwable: Throwable? = null) {
|
|
80
|
+
writer?.write(Level.ERROR.name, tag, message, throwable) ?: Log.e(tag, message, throwable)
|
|
81
|
+
}
|
|
82
|
+
}
|
package/android/src/main/java/org/infobip/reactlibrary/mobilemessaging/RNMMWebRTCUIService.kt
CHANGED
|
@@ -24,6 +24,67 @@ class RNMMWebRTCUIService(
|
|
|
24
24
|
|
|
25
25
|
companion object {
|
|
26
26
|
private var infobipRtcUiInstance: Any? = null
|
|
27
|
+
const val TAG = "RNMMWebRTCUI"
|
|
28
|
+
|
|
29
|
+
fun resetLogger(reactContext: ReactApplicationContext?) {
|
|
30
|
+
if (reactContext == null) {
|
|
31
|
+
RNMMLogger.w(TAG, "ReactContext is null, cannot enable native logs for WebRTCUI")
|
|
32
|
+
return
|
|
33
|
+
}
|
|
34
|
+
try {
|
|
35
|
+
val rtcUiLoggerClass = Class.forName("com.infobip.webrtc.ui.logging.RtcUiLogger")
|
|
36
|
+
val rtcUiLoggerInstance = rtcUiLoggerClass.getField("INSTANCE").get(null)
|
|
37
|
+
|
|
38
|
+
val resetMethod = rtcUiLoggerClass.getDeclaredMethod("reset")
|
|
39
|
+
resetMethod.isAccessible = true
|
|
40
|
+
resetMethod.invoke(rtcUiLoggerInstance)
|
|
41
|
+
} catch (e: ClassNotFoundException) {
|
|
42
|
+
// Ignored - Android WebRtcUi not enabled - no logs to enable
|
|
43
|
+
} catch (t: Throwable) {
|
|
44
|
+
RNMMLogger.e(TAG, "Cannot reset logger for WebRTCUI. Something went wrong.", t)
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
fun enforceLogsWriter(reactContext: ReactApplicationContext?, writer: RNMMLogWriter) {
|
|
49
|
+
if (reactContext == null) {
|
|
50
|
+
RNMMLogger.w(TAG, "ReactContext is null, cannot enable native logs for WebRTCUI")
|
|
51
|
+
return
|
|
52
|
+
}
|
|
53
|
+
try {
|
|
54
|
+
val rtcUiLoggerClass = Class.forName("com.infobip.webrtc.ui.logging.RtcUiLogger")
|
|
55
|
+
val rtcUiLoggerInstance = rtcUiLoggerClass.getField("INSTANCE").get(null)
|
|
56
|
+
|
|
57
|
+
val initMethod = rtcUiLoggerClass.getDeclaredMethod("init", Context::class.java)
|
|
58
|
+
initMethod.isAccessible = true
|
|
59
|
+
initMethod.invoke(rtcUiLoggerInstance, reactContext.applicationContext)
|
|
60
|
+
|
|
61
|
+
val enforceMethod = rtcUiLoggerClass.getDeclaredMethod("enforce")
|
|
62
|
+
enforceMethod.isAccessible = true
|
|
63
|
+
enforceMethod.invoke(rtcUiLoggerInstance)
|
|
64
|
+
|
|
65
|
+
val rtcUiWriterClass = Class.forName("com.infobip.webrtc.ui.logging.RtcUiWriter")
|
|
66
|
+
val writerInstance = java.lang.reflect.Proxy.newProxyInstance(rtcUiWriterClass.classLoader, arrayOf(rtcUiWriterClass)) { _, method, args ->
|
|
67
|
+
if ("write" == method.name) {
|
|
68
|
+
val level: Any? = args?.getOrNull(0)
|
|
69
|
+
val levelName: String? = (level as? Enum<*>)?.name
|
|
70
|
+
val tag: String = args?.getOrNull(1) as? String ?: ""
|
|
71
|
+
val message: String = args?.getOrNull(2) as? String ?: ""
|
|
72
|
+
val throwable: Throwable? = args?.getOrNull(3) as? Throwable
|
|
73
|
+
writer.write(levelName, tag, message, throwable)
|
|
74
|
+
}
|
|
75
|
+
null
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
val setWriterMethod = rtcUiLoggerClass.getDeclaredMethod("setWriter", rtcUiWriterClass)
|
|
79
|
+
setWriterMethod.isAccessible = true
|
|
80
|
+
setWriterMethod.invoke(rtcUiLoggerInstance, writerInstance)
|
|
81
|
+
} catch (e: ClassNotFoundException) {
|
|
82
|
+
// Ignored - Android WebRtcUi not enabled - no logs to enable
|
|
83
|
+
} catch (t: Throwable) {
|
|
84
|
+
RNMMLogger.e(TAG, "Cannot enable native logs for WebRTCUI. Something went wrong.", t)
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
27
88
|
}
|
|
28
89
|
|
|
29
90
|
private var successListenerClass: Class<*>? = null
|