rn-erxes-sdk 0.4.6 → 0.5.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/README.md +122 -38
- package/android/build.gradle +76 -0
- package/android/gradle.properties +7 -0
- package/android/src/main/AndroidManifest.xml +6 -0
- package/android/src/main/java/com/erxessdk/RnErxesSdkModule.kt +334 -0
- package/android/src/main/java/com/erxessdk/RnErxesSdkPackage.kt +15 -0
- package/lib/commonjs/ErxesMessenger.js +18 -8
- package/lib/commonjs/ErxesMessenger.js.map +1 -1
- package/lib/commonjs/nativeIos.js +3 -3
- package/lib/commonjs/nativeIos.js.map +1 -1
- package/lib/module/ErxesMessenger.js +18 -8
- package/lib/module/ErxesMessenger.js.map +1 -1
- package/lib/module/nativeIos.js +3 -3
- package/lib/module/nativeIos.js.map +1 -1
- package/lib/typescript/ErxesMessenger.d.ts +12 -2
- package/lib/typescript/ErxesMessenger.d.ts.map +1 -1
- package/lib/typescript/nativeIos.d.ts +7 -1
- package/lib/typescript/nativeIos.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/ErxesMessenger.tsx +35 -10
- package/src/nativeIos.ts +14 -4
package/README.md
CHANGED
|
@@ -106,25 +106,28 @@ Screenshots from the native [`erxes/erxes-ios-sdk`](https://github.com/erxes/erx
|
|
|
106
106
|
<img src="https://raw.githubusercontent.com/erxes/erxes-ios-sdk/main/screenshots/recent-chats.png" width="220" alt="Recent Chats">
|
|
107
107
|
</p>
|
|
108
108
|
|
|
109
|
-
### Android
|
|
109
|
+
### Android ✅ Available (chat mode)
|
|
110
110
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
111
|
+
Backed by the native [`erxes/erxes-android-sdk`](https://github.com/erxes/erxes-android-sdk).
|
|
112
|
+
Android currently implements **chat mode** (`displayMode: 'chat'`); the classic
|
|
113
|
+
floating launcher is iOS-only for now (`showLauncher`/`hideLauncher`/`hideMessenger`
|
|
114
|
+
are no-ops on Android). See [Requirements](#requirements).
|
|
114
115
|
|
|
115
116
|
## Roadmap
|
|
116
117
|
|
|
117
118
|
- [x] iOS native messenger (classic widget + chat mode)
|
|
118
|
-
- [
|
|
119
|
+
- [x] Android native messenger (chat mode)
|
|
120
|
+
- [ ] Android classic widget + floating launcher
|
|
119
121
|
|
|
120
122
|
---
|
|
121
123
|
|
|
122
124
|
# rn-erxes-sdk
|
|
123
125
|
|
|
124
|
-
A React Native bridge for the native SwiftUI
|
|
125
|
-
([`erxes/erxes-ios-sdk`](https://github.com/erxes/erxes-ios-sdk)
|
|
126
|
-
|
|
127
|
-
|
|
126
|
+
A React Native bridge for the native erxes messenger — SwiftUI on iOS
|
|
127
|
+
([`erxes/erxes-ios-sdk`](https://github.com/erxes/erxes-ios-sdk)) and Jetpack
|
|
128
|
+
Compose on Android ([`erxes/erxes-android-sdk`](https://github.com/erxes/erxes-android-sdk)).
|
|
129
|
+
iOS supports the classic widget and the full-screen **chat mode** (with voice
|
|
130
|
+
messages and header/drawer actions); Android supports chat mode.
|
|
128
131
|
|
|
129
132
|
```tsx
|
|
130
133
|
import { ErxesMessenger } from 'rn-erxes-sdk';
|
|
@@ -138,12 +141,13 @@ Two APIs are exported:
|
|
|
138
141
|
|
|
139
142
|
## Requirements
|
|
140
143
|
|
|
141
|
-
|
|
|
142
|
-
|
|
143
|
-
| iOS
|
|
144
|
-
| Swift
|
|
145
|
-
|
|
|
146
|
-
|
|
|
144
|
+
| | |
|
|
145
|
+
| ------------ | ----------------------------------------------------------- |
|
|
146
|
+
| iOS | 16.0+ |
|
|
147
|
+
| Swift | 5.9+ |
|
|
148
|
+
| Android | minSdk 24+, Java 17 |
|
|
149
|
+
| React Native | 0.81+ |
|
|
150
|
+
| Expo SDK | 53+ (development build or prebuild — Expo Go not supported) |
|
|
147
151
|
|
|
148
152
|
## Docs
|
|
149
153
|
|
|
@@ -180,6 +184,41 @@ cd ios && pod install
|
|
|
180
184
|
npx expo run:ios
|
|
181
185
|
```
|
|
182
186
|
|
|
187
|
+
### Android
|
|
188
|
+
|
|
189
|
+
Autolinking picks up the native module — no manual linking. Notes:
|
|
190
|
+
|
|
191
|
+
- **Chat mode only.** Use `displayMode="chat"`. `minSdk` must be `24+` and the app
|
|
192
|
+
compiles against Java 17.
|
|
193
|
+
- **Android SDK artifact.** The bridge depends on the native
|
|
194
|
+
`io.github.munkhorgilb:messenger-sdk:0.30.2`, resolved from Maven Central.
|
|
195
|
+
- **Action icons (optional).** To use Material icon names for `androidIcon` (e.g.
|
|
196
|
+
`"AccountCircle"`), add the full Compose Material icon set to your app:
|
|
197
|
+
|
|
198
|
+
```gradle
|
|
199
|
+
// android/app/build.gradle
|
|
200
|
+
dependencies {
|
|
201
|
+
implementation(platform("androidx.compose:compose-bom:2024.12.01"))
|
|
202
|
+
implementation("androidx.compose.material:material-icons-extended")
|
|
203
|
+
}
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
For release (R8/ProGuard) builds, keep the icon classes so name-based lookup
|
|
207
|
+
survives minification:
|
|
208
|
+
|
|
209
|
+
```pro
|
|
210
|
+
# android/app/proguard-rules.pro
|
|
211
|
+
-keep class androidx.compose.material.icons.filled.** { *; }
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
Alternatively, use a drawable resource instead of a Material icon (no extra
|
|
215
|
+
dependency) — see [Action icons](#action-icons-ios--android).
|
|
216
|
+
|
|
217
|
+
```bash
|
|
218
|
+
npx expo prebuild --platform android
|
|
219
|
+
npx expo run:android
|
|
220
|
+
```
|
|
221
|
+
|
|
183
222
|
## Usage — `<ErxesMessenger />` (recommended)
|
|
184
223
|
|
|
185
224
|
Render the component where the messenger should be active. It configures the SDK on
|
|
@@ -193,7 +232,7 @@ import { ErxesMessenger } from 'rn-erxes-sdk';
|
|
|
193
232
|
integrationId="YOUR_INTEGRATION_ID"
|
|
194
233
|
subDomain="yourcompany.erxes.io"
|
|
195
234
|
user={{ name: 'Jane Doe', email: 'user@example.com' }}
|
|
196
|
-
|
|
235
|
+
/>;
|
|
197
236
|
```
|
|
198
237
|
|
|
199
238
|
### Example 1 — Classic floating launcher
|
|
@@ -236,14 +275,15 @@ const isFocused = useIsFocused();
|
|
|
236
275
|
{
|
|
237
276
|
id: 'profile',
|
|
238
277
|
title: 'Profile',
|
|
239
|
-
|
|
278
|
+
iosIcon: 'person.crop.circle', // SF Symbol (iOS)
|
|
279
|
+
androidIcon: 'AccountCircle', // Material icon name (Android)
|
|
240
280
|
onPress: async ({ hide }) => {
|
|
241
281
|
await hide();
|
|
242
282
|
navigation.navigate('Profile', { user: CURRENT_USER });
|
|
243
283
|
},
|
|
244
284
|
},
|
|
245
285
|
]}
|
|
246
|
-
|
|
286
|
+
/>;
|
|
247
287
|
```
|
|
248
288
|
|
|
249
289
|
`renderLoading` shows your own UI until the connection handshake completes
|
|
@@ -267,7 +307,8 @@ messenger and pops the screen.
|
|
|
267
307
|
{
|
|
268
308
|
id: 'close',
|
|
269
309
|
title: 'Close',
|
|
270
|
-
|
|
310
|
+
iosIcon: 'xmark', // SF Symbol (iOS)
|
|
311
|
+
androidIcon: 'Close', // Material icon name (Android)
|
|
271
312
|
onPress: async ({ hide }) => {
|
|
272
313
|
await hide();
|
|
273
314
|
navigation.goBack();
|
|
@@ -281,26 +322,55 @@ messenger and pops the screen.
|
|
|
281
322
|
|
|
282
323
|
### Props
|
|
283
324
|
|
|
284
|
-
| Prop
|
|
285
|
-
|
|
286
|
-
| `integrationId`
|
|
287
|
-
| `endpoint` / `serverUrl` / `subDomain`
|
|
288
|
-
| `displayMode`
|
|
289
|
-
| `user`
|
|
290
|
-
| `cachedCustomerId`
|
|
291
|
-
| `primaryColor`
|
|
292
|
-
| `visible`
|
|
293
|
-
| `autoOpen`
|
|
294
|
-
| `autoHideOnUnmount`
|
|
295
|
-
| `launcherVisible`
|
|
296
|
-
| `homeActions` / `drawerActions`
|
|
297
|
-
| `renderLoading`
|
|
298
|
-
| `onLoad` / `onReady` / `onOpen` / `onClose` / `onError` | callbacks
|
|
299
|
-
| `onLoadingChange`
|
|
300
|
-
| `onAction`
|
|
325
|
+
| Prop | Type | Notes |
|
|
326
|
+
| ------------------------------------------------------- | ---------------------------- | ------------------------------------------------------------------------------------------------------------------ |
|
|
327
|
+
| `integrationId` | `string` | Required. |
|
|
328
|
+
| `endpoint` / `serverUrl` / `subDomain` | `string` | Provide one. `subDomain` accepts `'company.erxes.io'`. |
|
|
329
|
+
| `displayMode` | `'classic' \| 'chat'` | Defaults to `'classic'`. |
|
|
330
|
+
| `user` | `ErxesUser` | `{ name?, email?, phone?, customData? }`. |
|
|
331
|
+
| `cachedCustomerId` | `string` | Reuse a cached customer. |
|
|
332
|
+
| `primaryColor` | `string` | Hex accent, e.g. `'#3f78d9'`. |
|
|
333
|
+
| `visible` | `boolean` | Controlled show/hide on change. |
|
|
334
|
+
| `autoOpen` | `boolean` | Open after configure. Defaults to `true` in chat mode. |
|
|
335
|
+
| `autoHideOnUnmount` | `boolean` | Hide on unmount. Defaults to `true`. |
|
|
336
|
+
| `launcherVisible` | `boolean` | Show/hide the floating launcher after configure. |
|
|
337
|
+
| `homeActions` / `drawerActions` | `ErxesAction[]` | `{ id, title, iosIcon?, androidIcon?, onPress? }`. Chat mode only. See [Action icons](#action-icons-ios--android). |
|
|
338
|
+
| `renderLoading` | `() => ReactNode` | Rendered while configuring (between `onLoad` and `onReady`/`onError`), e.g. a spinner. Defaults to nothing. |
|
|
339
|
+
| `onLoad` / `onReady` / `onOpen` / `onClose` / `onError` | callbacks | Lifecycle events. |
|
|
340
|
+
| `onLoadingChange` | `(loading: boolean) => void` | Fired when the loading state changes (`true` while configuring). |
|
|
341
|
+
| `onAction` | `(id, helpers) => void` | Fallback for tapped actions with no `onPress`. |
|
|
301
342
|
|
|
302
343
|
Action `onPress` (and `onAction`) receive `ErxesMessengerHelpers`:
|
|
303
344
|
`show`, `hide`, `showLauncher`, `hideLauncher`, `setUser`, `clearUser`.
|
|
345
|
+
On Android, `showLauncher`/`hideLauncher`/`hide` are no-ops (chat mode only).
|
|
346
|
+
|
|
347
|
+
### Action icons (iOS & Android)
|
|
348
|
+
|
|
349
|
+
Each `homeActions` / `drawerActions` entry takes platform-specific icon fields —
|
|
350
|
+
the platform you're not running on is ignored:
|
|
351
|
+
|
|
352
|
+
| Field | Platform | Value |
|
|
353
|
+
| ------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
354
|
+
| `iosIcon` | iOS | An [SF Symbol](https://developer.apple.com/sf-symbols/) name, e.g. `'person.crop.circle'`. |
|
|
355
|
+
| `androidIcon` | Android | A Compose **Material icon name** (e.g. `'AccountCircle'`, `'Search'`) **or** a **drawable resource name** in your app (e.g. `'ic_profile'`). |
|
|
356
|
+
|
|
357
|
+
```tsx
|
|
358
|
+
homeActions={[
|
|
359
|
+
{ id: 'profile', title: 'Profile', iosIcon: 'person.crop.circle', androidIcon: 'AccountCircle' },
|
|
360
|
+
]}
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
On Android `androidIcon` resolves in order: Material icon name → drawable resource
|
|
364
|
+
→ the messenger's default icon if neither matches.
|
|
365
|
+
|
|
366
|
+
- **Material icon names** are the Compose `Icons.Filled.*` names in PascalCase.
|
|
367
|
+
Only a few ship in `material-icons-core`; for the full set add
|
|
368
|
+
`material-icons-extended` (and a release keep rule) — see
|
|
369
|
+
[Android setup](#android).
|
|
370
|
+
- **Drawable resources** need no extra dependency: drop a vector/PNG under
|
|
371
|
+
`android/app/src/main/res/drawable/` and pass its file name (without extension).
|
|
372
|
+
|
|
373
|
+
> `systemIcon` is still accepted as a deprecated alias for `iosIcon`.
|
|
304
374
|
|
|
305
375
|
## Advanced — `ErxesNativeIOS` (low-level)
|
|
306
376
|
|
|
@@ -353,8 +423,22 @@ ErxesNativeIOS.configure({
|
|
|
353
423
|
integrationId: 'YOUR_INTEGRATION_ID',
|
|
354
424
|
subDomain: 'yourcompany.erxes.io',
|
|
355
425
|
displayMode: 'chat',
|
|
356
|
-
homeActions: [
|
|
357
|
-
|
|
426
|
+
homeActions: [
|
|
427
|
+
{
|
|
428
|
+
id: 'orders',
|
|
429
|
+
title: 'My Orders',
|
|
430
|
+
iosIcon: 'bag',
|
|
431
|
+
androidIcon: 'ShoppingBag',
|
|
432
|
+
},
|
|
433
|
+
],
|
|
434
|
+
drawerActions: [
|
|
435
|
+
{
|
|
436
|
+
id: 'settings',
|
|
437
|
+
title: 'Settings',
|
|
438
|
+
iosIcon: 'gearshape',
|
|
439
|
+
androidIcon: 'Settings',
|
|
440
|
+
},
|
|
441
|
+
],
|
|
358
442
|
});
|
|
359
443
|
|
|
360
444
|
const sub = ErxesNativeIOS.addActionListener((id) => {
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
// Android native module for rn-erxes-sdk. Bridges the erxes Android Messenger
|
|
2
|
+
// SDK (io.github.munkhorgilb:messenger-sdk) to React Native, mirroring the iOS bridge in
|
|
3
|
+
// `ios/RnErxesSdk.swift`. Android currently implements chat mode only.
|
|
4
|
+
//
|
|
5
|
+
// Plugins (Android Gradle Plugin, Kotlin) come from the consuming app's
|
|
6
|
+
// buildscript classpath via React Native autolinking, so this module does not
|
|
7
|
+
// declare its own buildscript block — it is always built linked into an app
|
|
8
|
+
// (or an Expo prebuild), never standalone.
|
|
9
|
+
apply plugin: "com.android.library"
|
|
10
|
+
apply plugin: "org.jetbrains.kotlin.android"
|
|
11
|
+
|
|
12
|
+
def getExtOrDefault(name) {
|
|
13
|
+
return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties["RnErxesSdk_" + name]
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
def getExtOrIntegerDefault(name) {
|
|
17
|
+
return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties["RnErxesSdk_" + name]).toInteger()
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
android {
|
|
21
|
+
namespace "com.erxessdk"
|
|
22
|
+
|
|
23
|
+
compileSdkVersion getExtOrIntegerDefault("compileSdkVersion")
|
|
24
|
+
|
|
25
|
+
defaultConfig {
|
|
26
|
+
// The erxes Android SDK requires API 24+.
|
|
27
|
+
minSdkVersion Math.max(24, getExtOrIntegerDefault("minSdkVersion"))
|
|
28
|
+
targetSdkVersion getExtOrIntegerDefault("targetSdkVersion")
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
buildTypes {
|
|
32
|
+
release {
|
|
33
|
+
minifyEnabled false
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// The erxes Android SDK is compiled against Java 17.
|
|
38
|
+
compileOptions {
|
|
39
|
+
sourceCompatibility JavaVersion.VERSION_17
|
|
40
|
+
targetCompatibility JavaVersion.VERSION_17
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
kotlinOptions {
|
|
44
|
+
jvmTarget = "17"
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
repositories {
|
|
49
|
+
google()
|
|
50
|
+
mavenCentral()
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
dependencies {
|
|
54
|
+
// Version is supplied by the consuming app's React Native Gradle setup.
|
|
55
|
+
implementation "com.facebook.react:react-android"
|
|
56
|
+
|
|
57
|
+
// The erxes Android Messenger SDK (chat mode).
|
|
58
|
+
implementation "io.github.munkhorgilb:messenger-sdk:0.30.5"
|
|
59
|
+
|
|
60
|
+
// Needed at compile time to reference the Compose types in the SDK's public API:
|
|
61
|
+
// `Color` for `Appearance(primaryColor)` (ui-graphics) and `ImageVector`, which
|
|
62
|
+
// `ActionItem`'s constructor defaults reference (ui). The SDK pulls these
|
|
63
|
+
// transitively at runtime but exposes them as `implementation` (not `api`), so we
|
|
64
|
+
// depend on them explicitly. No Compose compiler is needed — these are referenced
|
|
65
|
+
// only as data types; this module has no @Composable code.
|
|
66
|
+
implementation platform("androidx.compose:compose-bom:2024.12.01")
|
|
67
|
+
implementation "androidx.compose.ui:ui"
|
|
68
|
+
implementation "androidx.compose.ui:ui-graphics"
|
|
69
|
+
// For resolving Material icons by name (the `Icons.Filled` receiver). Only the
|
|
70
|
+
// core icon set is bundled here; hosts add `material-icons-extended` for the
|
|
71
|
+
// full set (see README / docs).
|
|
72
|
+
implementation "androidx.compose.material:material-icons-core"
|
|
73
|
+
|
|
74
|
+
// For the StateFlow (isReady) collector on the main dispatcher.
|
|
75
|
+
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.9.0"
|
|
76
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# Fallback build settings used when the consuming app's root project does not
|
|
2
|
+
# define these in `ext` (e.g. standalone tooling). A real React Native app
|
|
3
|
+
# overrides these via its root build.gradle `ext` block.
|
|
4
|
+
RnErxesSdk_compileSdkVersion=35
|
|
5
|
+
RnErxesSdk_minSdkVersion=24
|
|
6
|
+
RnErxesSdk_targetSdkVersion=34
|
|
7
|
+
RnErxesSdk_kotlinVersion=2.0.21
|
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
package com.erxessdk
|
|
2
|
+
|
|
3
|
+
import androidx.compose.material.icons.Icons
|
|
4
|
+
import androidx.compose.ui.graphics.Color
|
|
5
|
+
import androidx.compose.ui.graphics.vector.ImageVector
|
|
6
|
+
import com.erxes.messenger.ErxesMessenger
|
|
7
|
+
import com.erxes.messenger.config.ActionItem
|
|
8
|
+
import com.erxes.messenger.config.Appearance
|
|
9
|
+
import com.erxes.messenger.config.DisplayMode
|
|
10
|
+
import com.erxes.messenger.config.MessengerConfig
|
|
11
|
+
import com.erxes.messenger.config.MessengerUser
|
|
12
|
+
import com.facebook.react.bridge.Arguments
|
|
13
|
+
import com.facebook.react.bridge.Promise
|
|
14
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
|
15
|
+
import com.facebook.react.bridge.ReactContextBaseJavaModule
|
|
16
|
+
import com.facebook.react.bridge.ReactMethod
|
|
17
|
+
import com.facebook.react.bridge.ReadableArray
|
|
18
|
+
import com.facebook.react.bridge.ReadableMap
|
|
19
|
+
import com.facebook.react.bridge.UiThreadUtil
|
|
20
|
+
import com.facebook.react.bridge.WritableMap
|
|
21
|
+
import com.facebook.react.modules.core.DeviceEventManagerModule
|
|
22
|
+
import kotlinx.coroutines.CoroutineScope
|
|
23
|
+
import kotlinx.coroutines.Dispatchers
|
|
24
|
+
import kotlinx.coroutines.SupervisorJob
|
|
25
|
+
import kotlinx.coroutines.cancel
|
|
26
|
+
import kotlinx.coroutines.flow.filter
|
|
27
|
+
import kotlinx.coroutines.launch
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* React Native bridge for the erxes Android Messenger SDK. Counterpart to the
|
|
31
|
+
* iOS `RnErxesSdk` (see `ios/RnErxesSdk.swift`); the native module name, method
|
|
32
|
+
* names, and event names match so the shared JS layer (`src/nativeIos.ts`) and
|
|
33
|
+
* `NativeEventEmitter` wiring work unchanged across platforms.
|
|
34
|
+
*
|
|
35
|
+
* Android implements **chat mode** only. The classic-mode launcher/imperative-hide
|
|
36
|
+
* methods (`showLauncher`/`hideLauncher`/`hideMessenger`) have no Android SDK
|
|
37
|
+
* equivalent and are no-ops here so the cross-platform JS contract resolves
|
|
38
|
+
* identically.
|
|
39
|
+
*/
|
|
40
|
+
class RnErxesSdkModule(private val reactContext: ReactApplicationContext) :
|
|
41
|
+
ReactContextBaseJavaModule(reactContext) {
|
|
42
|
+
|
|
43
|
+
/** Replaced on each `configure()`; collects `ErxesMessenger.isReady`. */
|
|
44
|
+
private var readyScope: CoroutineScope? = null
|
|
45
|
+
|
|
46
|
+
/** Active JS listener count — mirrors iOS `hasListeners` so we don't emit into the void. */
|
|
47
|
+
private var listenerCount = 0
|
|
48
|
+
|
|
49
|
+
override fun getName(): String = NAME
|
|
50
|
+
|
|
51
|
+
// region Configuration
|
|
52
|
+
|
|
53
|
+
@ReactMethod
|
|
54
|
+
fun configure(options: ReadableMap, promise: Promise) {
|
|
55
|
+
val integrationId = options.stringOrNull("integrationId")
|
|
56
|
+
if (integrationId.isNullOrEmpty()) {
|
|
57
|
+
promise.reject("missing_integration_id", "integrationId is required")
|
|
58
|
+
return
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
val endpoint = endpoint(options)
|
|
62
|
+
if (endpoint == null) {
|
|
63
|
+
promise.reject("missing_endpoint", "endpoint, serverUrl, or subDomain is required")
|
|
64
|
+
return
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Mirrors iOS: default to classic, opt into chat with displayMode: 'chat'.
|
|
68
|
+
val displayMode = when (options.stringOrNull("displayMode")) {
|
|
69
|
+
"chat" -> DisplayMode.CHAT
|
|
70
|
+
else -> DisplayMode.CLASSIC
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
val appearance = hexColor(options.stringOrNull("primaryColor"))
|
|
74
|
+
?.let { Appearance(primaryColor = it) }
|
|
75
|
+
?: Appearance()
|
|
76
|
+
|
|
77
|
+
val config = MessengerConfig(
|
|
78
|
+
endpoint = endpoint,
|
|
79
|
+
integrationId = integrationId,
|
|
80
|
+
cachedCustomerId = options.stringOrNull("cachedCustomerId"),
|
|
81
|
+
appearance = appearance,
|
|
82
|
+
displayMode = displayMode,
|
|
83
|
+
homeActions = actionItems(options.arrayOrNull("homeActions")),
|
|
84
|
+
drawerActions = actionItems(options.arrayOrNull("drawerActions")),
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
// Route chat-mode action taps to JS as `onErxesAction` events.
|
|
88
|
+
ErxesMessenger.onAction = { id ->
|
|
89
|
+
if (listenerCount > 0) {
|
|
90
|
+
emit(ACTION_EVENT, Arguments.createMap().apply { putString("id", id) })
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Forward the connect handshake to JS as `onErxesReady`. `isReady` is a
|
|
95
|
+
// StateFlow, so it replays its current value on collection (a `configure()`
|
|
96
|
+
// after the SDK is already connected still notifies JS) and conflates
|
|
97
|
+
// duplicates, so `filter { it }` emits once per connection — mirroring the
|
|
98
|
+
// iOS Combine pipeline (`removeDuplicates().filter { $0 }`).
|
|
99
|
+
readyScope?.cancel()
|
|
100
|
+
val scope = CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate)
|
|
101
|
+
readyScope = scope
|
|
102
|
+
scope.launch {
|
|
103
|
+
ErxesMessenger.isReady
|
|
104
|
+
.filter { it }
|
|
105
|
+
.collect {
|
|
106
|
+
if (listenerCount > 0) {
|
|
107
|
+
emit(READY_EVENT, null)
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// `configure()` registers chat-mode auto-present via activity lifecycle
|
|
113
|
+
// callbacks, so run it on the main thread.
|
|
114
|
+
UiThreadUtil.runOnUiThread {
|
|
115
|
+
ErxesMessenger.configure(reactContext.applicationContext, config)
|
|
116
|
+
|
|
117
|
+
// Present chat mode immediately (mirroring iOS, where `configure()` auto-
|
|
118
|
+
// presents). The SDK's own auto-present only fires on the *next* activity
|
|
119
|
+
// resume, but React Native calls `configure()` after the host activity is
|
|
120
|
+
// already resumed — so that event never comes. Present from the current
|
|
121
|
+
// activity instead. If there's no activity yet, the SDK's lifecycle
|
|
122
|
+
// fallback still covers it on the next resume.
|
|
123
|
+
if (displayMode == DisplayMode.CHAT) {
|
|
124
|
+
reactContext.currentActivity?.let { ErxesMessenger.show(it) }
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
promise.resolve(null)
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// endregion
|
|
132
|
+
|
|
133
|
+
// region User
|
|
134
|
+
|
|
135
|
+
@ReactMethod
|
|
136
|
+
fun setUser(options: ReadableMap, promise: Promise) {
|
|
137
|
+
// Note: iOS `MessengerUser` carries `customData`; the Android SDK's
|
|
138
|
+
// `MessengerUser` does not, so `customData` is accepted but ignored here.
|
|
139
|
+
ErxesMessenger.setUser(
|
|
140
|
+
MessengerUser(
|
|
141
|
+
email = options.stringOrNull("email"),
|
|
142
|
+
name = options.stringOrNull("name"),
|
|
143
|
+
phone = options.stringOrNull("phone"),
|
|
144
|
+
)
|
|
145
|
+
)
|
|
146
|
+
promise.resolve(null)
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
@ReactMethod
|
|
150
|
+
fun clearUser(promise: Promise) {
|
|
151
|
+
ErxesMessenger.clearUser()
|
|
152
|
+
promise.resolve(null)
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// endregion
|
|
156
|
+
|
|
157
|
+
// region Presentation
|
|
158
|
+
|
|
159
|
+
@ReactMethod
|
|
160
|
+
fun showMessenger(promise: Promise) {
|
|
161
|
+
val activity = reactContext.currentActivity
|
|
162
|
+
if (activity == null) {
|
|
163
|
+
promise.reject("missing_presenter", "Unable to find an activity to present from")
|
|
164
|
+
return
|
|
165
|
+
}
|
|
166
|
+
UiThreadUtil.runOnUiThread {
|
|
167
|
+
runCatching { ErxesMessenger.show(activity) }
|
|
168
|
+
.onSuccess { promise.resolve(null) }
|
|
169
|
+
.onFailure { promise.reject("show_failed", it.message, it) }
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// The launcher visibility / imperative-hide methods are classic-mode iOS
|
|
174
|
+
// concepts with no Android SDK equivalent (chat mode auto-presents and is
|
|
175
|
+
// dismissed by the user). No-op so the shared JS contract resolves identically.
|
|
176
|
+
|
|
177
|
+
@ReactMethod
|
|
178
|
+
fun hideMessenger(promise: Promise) {
|
|
179
|
+
promise.resolve(null)
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
@ReactMethod
|
|
183
|
+
fun showLauncher(promise: Promise) {
|
|
184
|
+
promise.resolve(null)
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
@ReactMethod
|
|
188
|
+
fun hideLauncher(promise: Promise) {
|
|
189
|
+
promise.resolve(null)
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// endregion
|
|
193
|
+
|
|
194
|
+
// region Event emitter plumbing (required by NativeEventEmitter on Android)
|
|
195
|
+
|
|
196
|
+
@ReactMethod
|
|
197
|
+
fun addListener(eventName: String) {
|
|
198
|
+
listenerCount += 1
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
@ReactMethod
|
|
202
|
+
fun removeListeners(count: Int) {
|
|
203
|
+
listenerCount = (listenerCount - count).coerceAtLeast(0)
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
override fun invalidate() {
|
|
207
|
+
readyScope?.cancel()
|
|
208
|
+
readyScope = null
|
|
209
|
+
ErxesMessenger.onAction = null
|
|
210
|
+
listenerCount = 0
|
|
211
|
+
super.invalidate()
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
private fun emit(name: String, body: WritableMap?) {
|
|
215
|
+
reactContext
|
|
216
|
+
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
|
|
217
|
+
.emit(name, body)
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// endregion
|
|
221
|
+
|
|
222
|
+
// region Parsing helpers (ported from the iOS bridge)
|
|
223
|
+
|
|
224
|
+
private fun endpoint(options: ReadableMap): String? {
|
|
225
|
+
options.stringOrNull("endpoint")?.let { return it }
|
|
226
|
+
options.stringOrNull("serverUrl")?.let { return it }
|
|
227
|
+
|
|
228
|
+
val subDomain = options.stringOrNull("subDomain") ?: return null
|
|
229
|
+
return if (subDomain.startsWith("http://") || subDomain.startsWith("https://")) {
|
|
230
|
+
subDomain
|
|
231
|
+
} else {
|
|
232
|
+
"https://$subDomain"
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Parse `[{ id, title, androidIcon }]` from JS into `[ActionItem]`. Entries
|
|
238
|
+
* without an `id` are skipped. `androidIcon` resolves, in order, to a Compose
|
|
239
|
+
* Material icon by name (e.g. `"AccountCircle"`, `"Search"`) or a host-app
|
|
240
|
+
* drawable resource name (e.g. `"ic_profile"`). When absent or unresolved, the
|
|
241
|
+
* messenger renders its default icon. The iOS `systemIcon` (an SF Symbol) has no
|
|
242
|
+
* Android equivalent and is ignored here.
|
|
243
|
+
*/
|
|
244
|
+
private fun actionItems(value: ReadableArray?): List<ActionItem> {
|
|
245
|
+
if (value == null) return emptyList()
|
|
246
|
+
val items = mutableListOf<ActionItem>()
|
|
247
|
+
for (i in 0 until value.size()) {
|
|
248
|
+
val map = value.getMap(i) ?: continue
|
|
249
|
+
val id = map.stringOrNull("id") ?: continue
|
|
250
|
+
val iconName = map.stringOrNull("androidIcon")
|
|
251
|
+
val vector = materialIcon(iconName)
|
|
252
|
+
items.add(
|
|
253
|
+
ActionItem(
|
|
254
|
+
id = id,
|
|
255
|
+
title = map.stringOrNull("title") ?: "",
|
|
256
|
+
imageVector = vector,
|
|
257
|
+
drawableRes = if (vector == null) drawableRes(iconName) else null,
|
|
258
|
+
)
|
|
259
|
+
)
|
|
260
|
+
}
|
|
261
|
+
return items
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Resolve a Compose Material (filled) icon by name, e.g. `"AccountCircle"` →
|
|
266
|
+
* `Icons.Filled.AccountCircle`. Only a handful of icons ship in
|
|
267
|
+
* `material-icons-core`; for the full set the host app must depend on
|
|
268
|
+
* `androidx.compose.material:material-icons-extended` (and keep these classes in
|
|
269
|
+
* release builds). Returns null if the name isn't a known Material icon.
|
|
270
|
+
*/
|
|
271
|
+
private fun materialIcon(name: String?): ImageVector? {
|
|
272
|
+
if (name.isNullOrEmpty()) return null
|
|
273
|
+
return try {
|
|
274
|
+
val cls = Class.forName("androidx.compose.material.icons.filled.${name}Kt")
|
|
275
|
+
val getter = cls.getMethod("get$name", Icons.Filled::class.java)
|
|
276
|
+
getter.invoke(null, Icons.Filled) as? ImageVector
|
|
277
|
+
} catch (t: Throwable) {
|
|
278
|
+
null
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/** Resolve a host-app drawable resource name to its id, or null if absent/unknown. */
|
|
283
|
+
private fun drawableRes(name: String?): Int? {
|
|
284
|
+
if (name.isNullOrEmpty()) return null
|
|
285
|
+
val id = reactContext.resources.getIdentifier(name, "drawable", reactContext.packageName)
|
|
286
|
+
return id.takeIf { it != 0 }
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/** Parse a `#RGB`/`#RRGGBB`/`#RRGGBBAA` hex string into a Compose [Color]. */
|
|
290
|
+
private fun hexColor(value: String?): Color? {
|
|
291
|
+
var hex = value?.trim()?.removePrefix("#") ?: return null
|
|
292
|
+
|
|
293
|
+
// Expand shorthand #RGB to #RRGGBB.
|
|
294
|
+
if (hex.length == 3) {
|
|
295
|
+
hex = hex.map { "$it$it" }.joinToString("")
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
if (hex.length != 6 && hex.length != 8) return null
|
|
299
|
+
val intValue = hex.toLongOrNull(16) ?: return null
|
|
300
|
+
|
|
301
|
+
return if (hex.length == 8) {
|
|
302
|
+
Color(
|
|
303
|
+
red = ((intValue shr 24) and 0xFF).toInt(),
|
|
304
|
+
green = ((intValue shr 16) and 0xFF).toInt(),
|
|
305
|
+
blue = ((intValue shr 8) and 0xFF).toInt(),
|
|
306
|
+
alpha = (intValue and 0xFF).toInt(),
|
|
307
|
+
)
|
|
308
|
+
} else {
|
|
309
|
+
Color(
|
|
310
|
+
red = ((intValue shr 16) and 0xFF).toInt(),
|
|
311
|
+
green = ((intValue shr 8) and 0xFF).toInt(),
|
|
312
|
+
blue = (intValue and 0xFF).toInt(),
|
|
313
|
+
)
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
private fun ReadableMap.stringOrNull(key: String): String? =
|
|
318
|
+
if (hasKey(key) && !isNull(key)) getString(key)?.ifEmpty { null } else null
|
|
319
|
+
|
|
320
|
+
private fun ReadableMap.arrayOrNull(key: String): ReadableArray? =
|
|
321
|
+
if (hasKey(key) && !isNull(key)) getArray(key) else null
|
|
322
|
+
|
|
323
|
+
// endregion
|
|
324
|
+
|
|
325
|
+
companion object {
|
|
326
|
+
const val NAME = "RnErxesSdk"
|
|
327
|
+
|
|
328
|
+
/** JS event fired when a chat-mode action is tapped. */
|
|
329
|
+
private const val ACTION_EVENT = "onErxesAction"
|
|
330
|
+
|
|
331
|
+
/** JS event fired when the connect handshake completes. */
|
|
332
|
+
private const val READY_EVENT = "onErxesReady"
|
|
333
|
+
}
|
|
334
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
package com.erxessdk
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.ReactPackage
|
|
4
|
+
import com.facebook.react.bridge.NativeModule
|
|
5
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
|
6
|
+
import com.facebook.react.uimanager.ViewManager
|
|
7
|
+
|
|
8
|
+
/** Registers [RnErxesSdkModule] with React Native. Discovered via autolinking. */
|
|
9
|
+
class RnErxesSdkPackage : ReactPackage {
|
|
10
|
+
override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> =
|
|
11
|
+
listOf(RnErxesSdkModule(reactContext))
|
|
12
|
+
|
|
13
|
+
override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> =
|
|
14
|
+
emptyList()
|
|
15
|
+
}
|
|
@@ -25,17 +25,27 @@ var _nativeIos = require("./nativeIos");
|
|
|
25
25
|
*/
|
|
26
26
|
|
|
27
27
|
/**
|
|
28
|
-
*
|
|
29
|
-
* (
|
|
30
|
-
*
|
|
28
|
+
* Map to the data-only shape the native bridge understands, dropping `onPress`
|
|
29
|
+
* (React Native cannot send JS functions to native — taps are dispatched on the
|
|
30
|
+
* JS side via the action listener). `iosIcon` (falling back to the deprecated
|
|
31
|
+
* `systemIcon`) becomes the iOS `systemIcon`; `androidIcon` is forwarded for
|
|
32
|
+
* Android to resolve to a drawable.
|
|
31
33
|
*/
|
|
32
34
|
function stripActions(actions) {
|
|
33
35
|
return actions.map(_ref => {
|
|
34
36
|
let {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
+
id,
|
|
38
|
+
title,
|
|
39
|
+
iosIcon,
|
|
40
|
+
systemIcon,
|
|
41
|
+
androidIcon
|
|
37
42
|
} = _ref;
|
|
38
|
-
return
|
|
43
|
+
return {
|
|
44
|
+
id,
|
|
45
|
+
title,
|
|
46
|
+
systemIcon: iosIcon ?? systemIcon ?? '',
|
|
47
|
+
androidIcon
|
|
48
|
+
};
|
|
39
49
|
});
|
|
40
50
|
}
|
|
41
51
|
|
|
@@ -102,7 +112,7 @@ function ErxesMessenger(_ref2) {
|
|
|
102
112
|
onActionRef.current = onAction;
|
|
103
113
|
}, [homeActions, drawerActions, onAction]);
|
|
104
114
|
(0, _react.useEffect)(() => {
|
|
105
|
-
if (_reactNative.Platform.OS !== 'ios') {
|
|
115
|
+
if (_reactNative.Platform.OS !== 'ios' && _reactNative.Platform.OS !== 'android') {
|
|
106
116
|
return;
|
|
107
117
|
}
|
|
108
118
|
setConfigured(false);
|
|
@@ -212,7 +222,7 @@ function ErxesMessenger(_ref2) {
|
|
|
212
222
|
// Wait until `configure()` has resolved — otherwise `showMessenger()` would
|
|
213
223
|
// race ahead of it and trip the native configure-before-show assertion. The
|
|
214
224
|
// initial open is handled in `setup()`; this only reacts to later changes.
|
|
215
|
-
if (_reactNative.Platform.OS !== 'ios' || visible === undefined || !configured) {
|
|
225
|
+
if (_reactNative.Platform.OS !== 'ios' && _reactNative.Platform.OS !== 'android' || visible === undefined || !configured) {
|
|
216
226
|
return;
|
|
217
227
|
}
|
|
218
228
|
if (visible && !shownRef.current) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_react","require","_reactNative","_nativeIos","stripActions","actions","map","_ref","
|
|
1
|
+
{"version":3,"names":["_react","require","_reactNative","_nativeIos","stripActions","actions","map","_ref","id","title","iosIcon","systemIcon","androidIcon","ErxesMessenger","_ref2","integrationId","endpoint","serverUrl","subDomain","displayMode","user","cachedCustomerId","primaryColor","visible","autoOpen","autoHideOnUnmount","launcherVisible","homeActions","drawerActions","renderLoading","onLoad","onReady","onOpen","onClose","onError","onAction","onLoadingChange","actionsRef","useRef","onActionRef","onLoadingChangeRef","shownRef","configured","setConfigured","useState","loading","setLoading","useEffect","current","_onLoadingChangeRef$c","call","Platform","OS","helpers","show","ErxesNativeIOS","showMessenger","hide","hideMessenger","showLauncher","hideLauncher","setUser","nextUser","clearUser","sub","addActionListener","_onActionRef$current","action","find","item","onPress","readySub","addReadyListener","setup","configure","shouldOpen","error","remove","undefined"],"sourceRoot":"../../src","sources":["ErxesMessenger.tsx"],"mappings":"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"}
|
|
@@ -16,11 +16,11 @@ const ACTION_EVENT = 'onErxesAction';
|
|
|
16
16
|
|
|
17
17
|
/** Native event name emitted when the connect handshake completes. */
|
|
18
18
|
const READY_EVENT = 'onErxesReady';
|
|
19
|
-
const LINKING_ERROR = "The rn-erxes-sdk native iOS module is not linked. Run `pod install` in your app's ios directory and rebuild the app.";
|
|
19
|
+
const LINKING_ERROR = _reactNative.Platform.OS === 'android' ? 'The rn-erxes-sdk native Android module is not linked. Rebuild the Android app (e.g. `npx react-native run-android`).' : "The rn-erxes-sdk native iOS module is not linked. Run `pod install` in your app's ios directory and rebuild the app.";
|
|
20
20
|
const nativeModule = _reactNative.NativeModules.RnErxesSdk;
|
|
21
21
|
function getNativeModule() {
|
|
22
|
-
if (_reactNative.Platform.OS !== 'ios') {
|
|
23
|
-
throw new Error('Erxes native messenger is only available on iOS.');
|
|
22
|
+
if (_reactNative.Platform.OS !== 'ios' && _reactNative.Platform.OS !== 'android') {
|
|
23
|
+
throw new Error('Erxes native messenger is only available on iOS and Android.');
|
|
24
24
|
}
|
|
25
25
|
if (!nativeModule) {
|
|
26
26
|
throw new Error(LINKING_ERROR);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_reactNative","require","ACTION_EVENT","READY_EVENT","LINKING_ERROR","
|
|
1
|
+
{"version":3,"names":["_reactNative","require","ACTION_EVENT","READY_EVENT","LINKING_ERROR","Platform","OS","nativeModule","NativeModules","RnErxesSdk","getNativeModule","Error","ErxesNativeIOS","configure","options","setUser","customData","Object","fromEntries","entries","filter","_ref","value","undefined","map","_ref2","key","String","clearUser","showMessenger","showLauncher","hideLauncher","hideMessenger","addActionListener","handler","emitter","NativeEventEmitter","addListener","event","id","addReadyListener","exports"],"sourceRoot":"../../src","sources":["nativeIos.ts"],"mappings":";;;;;;AAAA,IAAAA,YAAA,GAAAC,OAAA;AAQA;AACA;AACA;AACA;AACA;;AAiDA;AACA,MAAMC,YAAY,GAAG,eAAe;;AAEpC;AACA,MAAMC,WAAW,GAAG,cAAc;AAElC,MAAMC,aAAa,GACjBC,qBAAQ,CAACC,EAAE,KAAK,SAAS,GACrB,sHAAsH,GACtH,sHAAsH;AAE5H,MAAMC,YAAY,GAAGC,0BAAa,CAACC,UAAyC;AAE5E,SAASC,eAAeA,CAAA,EAAoB;EAC1C,IAAIL,qBAAQ,CAACC,EAAE,KAAK,KAAK,IAAID,qBAAQ,CAACC,EAAE,KAAK,SAAS,EAAE;IACtD,MAAM,IAAIK,KAAK,CACb,8DACF,CAAC;EACH;EAEA,IAAI,CAACJ,YAAY,EAAE;IACjB,MAAM,IAAII,KAAK,CAACP,aAAa,CAAC;EAChC;EAEA,OAAOG,YAAY;AACrB;AAEO,MAAMK,cAAc,GAAG;EAC5BC,SAASA,CAACC,OAAwB,EAAE;IAClC,OAAOJ,eAAe,CAAC,CAAC,CAACG,SAAS,CAACC,OAAO,CAAC;EAC7C,CAAC;EACDC,OAAOA,CAACD,OAAsB,EAAE;IAC9B,MAAME,UAAU,GAAGC,MAAM,CAACC,WAAW,CACnCD,MAAM,CAACE,OAAO,CAACL,OAAO,CAACE,UAAU,IAAI,CAAC,CAAC,CAAC,CACrCI,MAAM,CAACC,IAAA;MAAA,IAAC,GAAGC,KAAK,CAAC,GAAAD,IAAA;MAAA,OAAKC,KAAK,KAAK,IAAI,IAAIA,KAAK,KAAKC,SAAS;IAAA,EAAC,CAC5DC,GAAG,CAACC,KAAA;MAAA,IAAC,CAACC,GAAG,EAAEJ,KAAK,CAAC,GAAAG,KAAA;MAAA,OAAK,CAACC,GAAG,EAAEC,MAAM,CAACL,KAAK,CAAC,CAAC;IAAA,EAC/C,CAAC;IAED,OAAOZ,eAAe,CAAC,CAAC,CAACK,OAAO,CAAC;MAC/B,GAAGD,OAAO;MACVE;IACF,CAAC,CAAC;EACJ,CAAC;EACDY,SAASA,CAAA,EAAG;IACV,OAAOlB,eAAe,CAAC,CAAC,CAACkB,SAAS,CAAC,CAAC;EACtC,CAAC;EACDC,aAAaA,CAAA,EAAG;IACd,OAAOnB,eAAe,CAAC,CAAC,CAACmB,aAAa,CAAC,CAAC;EAC1C,CAAC;EACDC,YAAYA,CAAA,EAAG;IACb,OAAOpB,eAAe,CAAC,CAAC,CAACoB,YAAY,CAAC,CAAC;EACzC,CAAC;EACDC,YAAYA,CAAA,EAAG;IACb,OAAOrB,eAAe,CAAC,CAAC,CAACqB,YAAY,CAAC,CAAC;EACzC,CAAC;EACDC,aAAaA,CAAA,EAAG;IACd,OAAOtB,eAAe,CAAC,CAAC,CAACsB,aAAa,CAAC,CAAC;EAC1C,CAAC;EACD;AACF;AACA;AACA;AACA;AACA;EACEC,iBAAiBA,CAACC,OAA6B,EAAuB;IACpE,MAAMC,OAAO,GAAG,IAAIC,+BAAkB,CACpC1B,eAAe,CAAC,CAClB,CAAC;IACD,OAAOyB,OAAO,CAACE,WAAW,CAACnC,YAAY,EAAGoC,KAAqB,IAC7DJ,OAAO,CAACI,KAAK,CAACC,EAAE,CAClB,CAAC;EACH,CAAC;EACD;AACF;AACA;AACA;AACA;AACA;EACEC,gBAAgBA,CAACN,OAAmB,EAAuB;IACzD,MAAMC,OAAO,GAAG,IAAIC,+BAAkB,CACpC1B,eAAe,CAAC,CAClB,CAAC;IACD,OAAOyB,OAAO,CAACE,WAAW,CAAClC,WAAW,EAAE,MAAM+B,OAAO,CAAC,CAAC,CAAC;EAC1D;AACF,CAAC;AAACO,OAAA,CAAA7B,cAAA,GAAAA,cAAA"}
|
|
@@ -20,17 +20,27 @@ import { ErxesNativeIOS } from './nativeIos';
|
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
|
-
*
|
|
24
|
-
* (
|
|
25
|
-
*
|
|
23
|
+
* Map to the data-only shape the native bridge understands, dropping `onPress`
|
|
24
|
+
* (React Native cannot send JS functions to native — taps are dispatched on the
|
|
25
|
+
* JS side via the action listener). `iosIcon` (falling back to the deprecated
|
|
26
|
+
* `systemIcon`) becomes the iOS `systemIcon`; `androidIcon` is forwarded for
|
|
27
|
+
* Android to resolve to a drawable.
|
|
26
28
|
*/
|
|
27
29
|
function stripActions(actions) {
|
|
28
30
|
return actions.map(_ref => {
|
|
29
31
|
let {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
+
id,
|
|
33
|
+
title,
|
|
34
|
+
iosIcon,
|
|
35
|
+
systemIcon,
|
|
36
|
+
androidIcon
|
|
32
37
|
} = _ref;
|
|
33
|
-
return
|
|
38
|
+
return {
|
|
39
|
+
id,
|
|
40
|
+
title,
|
|
41
|
+
systemIcon: iosIcon ?? systemIcon ?? '',
|
|
42
|
+
androidIcon
|
|
43
|
+
};
|
|
34
44
|
});
|
|
35
45
|
}
|
|
36
46
|
|
|
@@ -97,7 +107,7 @@ export function ErxesMessenger(_ref2) {
|
|
|
97
107
|
onActionRef.current = onAction;
|
|
98
108
|
}, [homeActions, drawerActions, onAction]);
|
|
99
109
|
useEffect(() => {
|
|
100
|
-
if (Platform.OS !== 'ios') {
|
|
110
|
+
if (Platform.OS !== 'ios' && Platform.OS !== 'android') {
|
|
101
111
|
return;
|
|
102
112
|
}
|
|
103
113
|
setConfigured(false);
|
|
@@ -207,7 +217,7 @@ export function ErxesMessenger(_ref2) {
|
|
|
207
217
|
// Wait until `configure()` has resolved — otherwise `showMessenger()` would
|
|
208
218
|
// race ahead of it and trip the native configure-before-show assertion. The
|
|
209
219
|
// initial open is handled in `setup()`; this only reacts to later changes.
|
|
210
|
-
if (Platform.OS !== 'ios' || visible === undefined || !configured) {
|
|
220
|
+
if (Platform.OS !== 'ios' && Platform.OS !== 'android' || visible === undefined || !configured) {
|
|
211
221
|
return;
|
|
212
222
|
}
|
|
213
223
|
if (visible && !shownRef.current) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["useEffect","useRef","useState","Platform","ErxesNativeIOS","stripActions","actions","map","_ref","
|
|
1
|
+
{"version":3,"names":["useEffect","useRef","useState","Platform","ErxesNativeIOS","stripActions","actions","map","_ref","id","title","iosIcon","systemIcon","androidIcon","ErxesMessenger","_ref2","integrationId","endpoint","serverUrl","subDomain","displayMode","user","cachedCustomerId","primaryColor","visible","autoOpen","autoHideOnUnmount","launcherVisible","homeActions","drawerActions","renderLoading","onLoad","onReady","onOpen","onClose","onError","onAction","onLoadingChange","actionsRef","onActionRef","onLoadingChangeRef","shownRef","configured","setConfigured","loading","setLoading","current","_onLoadingChangeRef$c","call","OS","helpers","show","showMessenger","hide","hideMessenger","showLauncher","hideLauncher","setUser","nextUser","clearUser","sub","addActionListener","_onActionRef$current","action","find","item","onPress","readySub","addReadyListener","setup","configure","shouldOpen","error","remove","undefined"],"sourceRoot":"../../src","sources":["ErxesMessenger.tsx"],"mappings":"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"}
|
package/lib/module/nativeIos.js
CHANGED
|
@@ -11,11 +11,11 @@ const ACTION_EVENT = 'onErxesAction';
|
|
|
11
11
|
|
|
12
12
|
/** Native event name emitted when the connect handshake completes. */
|
|
13
13
|
const READY_EVENT = 'onErxesReady';
|
|
14
|
-
const LINKING_ERROR = "The rn-erxes-sdk native iOS module is not linked. Run `pod install` in your app's ios directory and rebuild the app.";
|
|
14
|
+
const LINKING_ERROR = Platform.OS === 'android' ? 'The rn-erxes-sdk native Android module is not linked. Rebuild the Android app (e.g. `npx react-native run-android`).' : "The rn-erxes-sdk native iOS module is not linked. Run `pod install` in your app's ios directory and rebuild the app.";
|
|
15
15
|
const nativeModule = NativeModules.RnErxesSdk;
|
|
16
16
|
function getNativeModule() {
|
|
17
|
-
if (Platform.OS !== 'ios') {
|
|
18
|
-
throw new Error('Erxes native messenger is only available on iOS.');
|
|
17
|
+
if (Platform.OS !== 'ios' && Platform.OS !== 'android') {
|
|
18
|
+
throw new Error('Erxes native messenger is only available on iOS and Android.');
|
|
19
19
|
}
|
|
20
20
|
if (!nativeModule) {
|
|
21
21
|
throw new Error(LINKING_ERROR);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["NativeEventEmitter","NativeModules","Platform","ACTION_EVENT","READY_EVENT","LINKING_ERROR","nativeModule","RnErxesSdk","getNativeModule","
|
|
1
|
+
{"version":3,"names":["NativeEventEmitter","NativeModules","Platform","ACTION_EVENT","READY_EVENT","LINKING_ERROR","OS","nativeModule","RnErxesSdk","getNativeModule","Error","ErxesNativeIOS","configure","options","setUser","customData","Object","fromEntries","entries","filter","_ref","value","undefined","map","_ref2","key","String","clearUser","showMessenger","showLauncher","hideLauncher","hideMessenger","addActionListener","handler","emitter","addListener","event","id","addReadyListener"],"sourceRoot":"../../src","sources":["nativeIos.ts"],"mappings":"AAAA,SACEA,kBAAkB,EAClBC,aAAa,EACbC,QAAQ,QAGH,cAAc;;AAErB;AACA;AACA;AACA;AACA;;AAiDA;AACA,MAAMC,YAAY,GAAG,eAAe;;AAEpC;AACA,MAAMC,WAAW,GAAG,cAAc;AAElC,MAAMC,aAAa,GACjBH,QAAQ,CAACI,EAAE,KAAK,SAAS,GACrB,sHAAsH,GACtH,sHAAsH;AAE5H,MAAMC,YAAY,GAAGN,aAAa,CAACO,UAAyC;AAE5E,SAASC,eAAeA,CAAA,EAAoB;EAC1C,IAAIP,QAAQ,CAACI,EAAE,KAAK,KAAK,IAAIJ,QAAQ,CAACI,EAAE,KAAK,SAAS,EAAE;IACtD,MAAM,IAAII,KAAK,CACb,8DACF,CAAC;EACH;EAEA,IAAI,CAACH,YAAY,EAAE;IACjB,MAAM,IAAIG,KAAK,CAACL,aAAa,CAAC;EAChC;EAEA,OAAOE,YAAY;AACrB;AAEA,OAAO,MAAMI,cAAc,GAAG;EAC5BC,SAASA,CAACC,OAAwB,EAAE;IAClC,OAAOJ,eAAe,CAAC,CAAC,CAACG,SAAS,CAACC,OAAO,CAAC;EAC7C,CAAC;EACDC,OAAOA,CAACD,OAAsB,EAAE;IAC9B,MAAME,UAAU,GAAGC,MAAM,CAACC,WAAW,CACnCD,MAAM,CAACE,OAAO,CAACL,OAAO,CAACE,UAAU,IAAI,CAAC,CAAC,CAAC,CACrCI,MAAM,CAACC,IAAA;MAAA,IAAC,GAAGC,KAAK,CAAC,GAAAD,IAAA;MAAA,OAAKC,KAAK,KAAK,IAAI,IAAIA,KAAK,KAAKC,SAAS;IAAA,EAAC,CAC5DC,GAAG,CAACC,KAAA;MAAA,IAAC,CAACC,GAAG,EAAEJ,KAAK,CAAC,GAAAG,KAAA;MAAA,OAAK,CAACC,GAAG,EAAEC,MAAM,CAACL,KAAK,CAAC,CAAC;IAAA,EAC/C,CAAC;IAED,OAAOZ,eAAe,CAAC,CAAC,CAACK,OAAO,CAAC;MAC/B,GAAGD,OAAO;MACVE;IACF,CAAC,CAAC;EACJ,CAAC;EACDY,SAASA,CAAA,EAAG;IACV,OAAOlB,eAAe,CAAC,CAAC,CAACkB,SAAS,CAAC,CAAC;EACtC,CAAC;EACDC,aAAaA,CAAA,EAAG;IACd,OAAOnB,eAAe,CAAC,CAAC,CAACmB,aAAa,CAAC,CAAC;EAC1C,CAAC;EACDC,YAAYA,CAAA,EAAG;IACb,OAAOpB,eAAe,CAAC,CAAC,CAACoB,YAAY,CAAC,CAAC;EACzC,CAAC;EACDC,YAAYA,CAAA,EAAG;IACb,OAAOrB,eAAe,CAAC,CAAC,CAACqB,YAAY,CAAC,CAAC;EACzC,CAAC;EACDC,aAAaA,CAAA,EAAG;IACd,OAAOtB,eAAe,CAAC,CAAC,CAACsB,aAAa,CAAC,CAAC;EAC1C,CAAC;EACD;AACF;AACA;AACA;AACA;AACA;EACEC,iBAAiBA,CAACC,OAA6B,EAAuB;IACpE,MAAMC,OAAO,GAAG,IAAIlC,kBAAkB,CACpCS,eAAe,CAAC,CAClB,CAAC;IACD,OAAOyB,OAAO,CAACC,WAAW,CAAChC,YAAY,EAAGiC,KAAqB,IAC7DH,OAAO,CAACG,KAAK,CAACC,EAAE,CAClB,CAAC;EACH,CAAC;EACD;AACF;AACA;AACA;AACA;AACA;EACEC,gBAAgBA,CAACL,OAAmB,EAAuB;IACzD,MAAMC,OAAO,GAAG,IAAIlC,kBAAkB,CACpCS,eAAe,CAAC,CAClB,CAAC;IACD,OAAOyB,OAAO,CAACC,WAAW,CAAC/B,WAAW,EAAE,MAAM6B,OAAO,CAAC,CAAC,CAAC;EAC1D;AACF,CAAC"}
|
|
@@ -28,8 +28,18 @@ export type ErxesAction = {
|
|
|
28
28
|
id: string;
|
|
29
29
|
/** Display title (drawer rows / accessibility label for header icons). */
|
|
30
30
|
title: string;
|
|
31
|
-
/** SF Symbol name, e.g. "person.crop.circle". */
|
|
32
|
-
|
|
31
|
+
/** iOS SF Symbol name, e.g. "person.crop.circle". */
|
|
32
|
+
iosIcon?: string;
|
|
33
|
+
/**
|
|
34
|
+
* Android drawable resource name in your app, e.g. `"ic_profile"`. Add the
|
|
35
|
+
* drawable under `android/app/src/main/res/drawable/`. When omitted or not
|
|
36
|
+
* found, the messenger renders its default icon.
|
|
37
|
+
*/
|
|
38
|
+
androidIcon?: string;
|
|
39
|
+
/**
|
|
40
|
+
* @deprecated Use {@link iosIcon}. Kept as an alias for the iOS SF Symbol.
|
|
41
|
+
*/
|
|
42
|
+
systemIcon?: string;
|
|
33
43
|
/** Runs when this action is tapped. Receives imperative {@link ErxesMessengerHelpers}. */
|
|
34
44
|
onPress?: (helpers: ErxesMessengerHelpers) => void | Promise<void>;
|
|
35
45
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ErxesMessenger.d.ts","sourceRoot":"","sources":["../../src/ErxesMessenger.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA+B,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAGpE,OAAO,
|
|
1
|
+
{"version":3,"file":"ErxesMessenger.d.ts","sourceRoot":"","sources":["../../src/ErxesMessenger.tsx"],"names":[],"mappings":"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"}
|
|
@@ -9,8 +9,14 @@ type NativeIOSAction = {
|
|
|
9
9
|
id: string;
|
|
10
10
|
/** Display title (drawer rows / accessibility label for header icons). */
|
|
11
11
|
title: string;
|
|
12
|
-
/** SF Symbol name, e.g. "magnifyingglass". */
|
|
12
|
+
/** iOS SF Symbol name, e.g. "magnifyingglass". Ignored on Android. */
|
|
13
13
|
systemIcon: string;
|
|
14
|
+
/**
|
|
15
|
+
* Android drawable resource name in the host app (e.g. `"ic_profile"`),
|
|
16
|
+
* resolved to a drawable at runtime. Ignored on iOS. When omitted (or not
|
|
17
|
+
* found), the messenger renders its default icon.
|
|
18
|
+
*/
|
|
19
|
+
androidIcon?: string;
|
|
14
20
|
};
|
|
15
21
|
type NativeIOSConfig = {
|
|
16
22
|
integrationId: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nativeIos.d.ts","sourceRoot":"","sources":["../../src/nativeIos.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,mBAAmB,EAEzB,MAAM,cAAc,CAAC;AAEtB;;;;GAIG;AACH,KAAK,eAAe,GAAG;IACrB,wDAAwD;IACxD,EAAE,EAAE,MAAM,CAAC;IACX,0EAA0E;IAC1E,KAAK,EAAE,MAAM,CAAC;IACd,
|
|
1
|
+
{"version":3,"file":"nativeIos.d.ts","sourceRoot":"","sources":["../../src/nativeIos.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,mBAAmB,EAEzB,MAAM,cAAc,CAAC;AAEtB;;;;GAIG;AACH,KAAK,eAAe,GAAG;IACrB,wDAAwD;IACxD,EAAE,EAAE,MAAM,CAAC;IACX,0EAA0E;IAC1E,KAAK,EAAE,MAAM,CAAC;IACd,sEAAsE;IACtE,UAAU,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,KAAK,eAAe,GAAG;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,6EAA6E;IAC7E,WAAW,CAAC,EAAE,SAAS,GAAG,MAAM,CAAC;IACjC,8DAA8D;IAC9D,WAAW,CAAC,EAAE,eAAe,EAAE,CAAC;IAChC,gEAAgE;IAChE,aAAa,CAAC,EAAE,eAAe,EAAE,CAAC;IAClC,8DAA8D;IAC9D,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,KAAK,aAAa,GAAG;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC;CAC3E,CAAC;AAuCF,eAAO,MAAM,cAAc;uBACN,eAAe;qBAGjB,aAAa;;;;;;IA2B9B;;;;;OAKG;oCAC6B,MAAM,KAAK,IAAI,GAAG,mBAAmB;IAQrE;;;;;OAKG;8BACuB,MAAM,IAAI,GAAG,mBAAmB;CAM3D,CAAC;AAEF,YAAY,EAAE,eAAe,EAAE,eAAe,EAAE,aAAa,EAAE,CAAC"}
|
package/package.json
CHANGED
package/src/ErxesMessenger.tsx
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import { useEffect, useRef, useState, type ReactNode } from 'react';
|
|
2
2
|
import { Platform } from 'react-native';
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
ErxesNativeIOS,
|
|
6
|
+
type NativeIOSAction,
|
|
7
|
+
type NativeIOSUser,
|
|
8
|
+
} from './nativeIos';
|
|
5
9
|
|
|
6
10
|
/**
|
|
7
11
|
* The identified end user. Same shape the native bridge expects — passing
|
|
@@ -33,8 +37,18 @@ export type ErxesAction = {
|
|
|
33
37
|
id: string;
|
|
34
38
|
/** Display title (drawer rows / accessibility label for header icons). */
|
|
35
39
|
title: string;
|
|
36
|
-
/** SF Symbol name, e.g. "person.crop.circle". */
|
|
37
|
-
|
|
40
|
+
/** iOS SF Symbol name, e.g. "person.crop.circle". */
|
|
41
|
+
iosIcon?: string;
|
|
42
|
+
/**
|
|
43
|
+
* Android drawable resource name in your app, e.g. `"ic_profile"`. Add the
|
|
44
|
+
* drawable under `android/app/src/main/res/drawable/`. When omitted or not
|
|
45
|
+
* found, the messenger renders its default icon.
|
|
46
|
+
*/
|
|
47
|
+
androidIcon?: string;
|
|
48
|
+
/**
|
|
49
|
+
* @deprecated Use {@link iosIcon}. Kept as an alias for the iOS SF Symbol.
|
|
50
|
+
*/
|
|
51
|
+
systemIcon?: string;
|
|
38
52
|
/** Runs when this action is tapped. Receives imperative {@link ErxesMessengerHelpers}. */
|
|
39
53
|
onPress?: (helpers: ErxesMessengerHelpers) => void | Promise<void>;
|
|
40
54
|
};
|
|
@@ -102,12 +116,19 @@ export type ErxesMessengerProps = {
|
|
|
102
116
|
};
|
|
103
117
|
|
|
104
118
|
/**
|
|
105
|
-
*
|
|
106
|
-
* (
|
|
107
|
-
*
|
|
119
|
+
* Map to the data-only shape the native bridge understands, dropping `onPress`
|
|
120
|
+
* (React Native cannot send JS functions to native — taps are dispatched on the
|
|
121
|
+
* JS side via the action listener). `iosIcon` (falling back to the deprecated
|
|
122
|
+
* `systemIcon`) becomes the iOS `systemIcon`; `androidIcon` is forwarded for
|
|
123
|
+
* Android to resolve to a drawable.
|
|
108
124
|
*/
|
|
109
|
-
function stripActions(actions: ErxesAction[]) {
|
|
110
|
-
return actions.map(({
|
|
125
|
+
function stripActions(actions: ErxesAction[]): NativeIOSAction[] {
|
|
126
|
+
return actions.map(({ id, title, iosIcon, systemIcon, androidIcon }) => ({
|
|
127
|
+
id,
|
|
128
|
+
title,
|
|
129
|
+
systemIcon: iosIcon ?? systemIcon ?? '',
|
|
130
|
+
androidIcon,
|
|
131
|
+
}));
|
|
111
132
|
}
|
|
112
133
|
|
|
113
134
|
/**
|
|
@@ -175,7 +196,7 @@ export function ErxesMessenger({
|
|
|
175
196
|
}, [homeActions, drawerActions, onAction]);
|
|
176
197
|
|
|
177
198
|
useEffect(() => {
|
|
178
|
-
if (Platform.OS !== 'ios') {
|
|
199
|
+
if (Platform.OS !== 'ios' && Platform.OS !== 'android') {
|
|
179
200
|
return;
|
|
180
201
|
}
|
|
181
202
|
|
|
@@ -299,7 +320,11 @@ export function ErxesMessenger({
|
|
|
299
320
|
// Wait until `configure()` has resolved — otherwise `showMessenger()` would
|
|
300
321
|
// race ahead of it and trip the native configure-before-show assertion. The
|
|
301
322
|
// initial open is handled in `setup()`; this only reacts to later changes.
|
|
302
|
-
if (
|
|
323
|
+
if (
|
|
324
|
+
(Platform.OS !== 'ios' && Platform.OS !== 'android') ||
|
|
325
|
+
visible === undefined ||
|
|
326
|
+
!configured
|
|
327
|
+
) {
|
|
303
328
|
return;
|
|
304
329
|
}
|
|
305
330
|
|
package/src/nativeIos.ts
CHANGED
|
@@ -16,8 +16,14 @@ type NativeIOSAction = {
|
|
|
16
16
|
id: string;
|
|
17
17
|
/** Display title (drawer rows / accessibility label for header icons). */
|
|
18
18
|
title: string;
|
|
19
|
-
/** SF Symbol name, e.g. "magnifyingglass". */
|
|
19
|
+
/** iOS SF Symbol name, e.g. "magnifyingglass". Ignored on Android. */
|
|
20
20
|
systemIcon: string;
|
|
21
|
+
/**
|
|
22
|
+
* Android drawable resource name in the host app (e.g. `"ic_profile"`),
|
|
23
|
+
* resolved to a drawable at runtime. Ignored on iOS. When omitted (or not
|
|
24
|
+
* found), the messenger renders its default icon.
|
|
25
|
+
*/
|
|
26
|
+
androidIcon?: string;
|
|
21
27
|
};
|
|
22
28
|
|
|
23
29
|
type NativeIOSConfig = {
|
|
@@ -60,13 +66,17 @@ const ACTION_EVENT = 'onErxesAction';
|
|
|
60
66
|
const READY_EVENT = 'onErxesReady';
|
|
61
67
|
|
|
62
68
|
const LINKING_ERROR =
|
|
63
|
-
|
|
69
|
+
Platform.OS === 'android'
|
|
70
|
+
? 'The rn-erxes-sdk native Android module is not linked. Rebuild the Android app (e.g. `npx react-native run-android`).'
|
|
71
|
+
: "The rn-erxes-sdk native iOS module is not linked. Run `pod install` in your app's ios directory and rebuild the app.";
|
|
64
72
|
|
|
65
73
|
const nativeModule = NativeModules.RnErxesSdk as NativeIOSModule | undefined;
|
|
66
74
|
|
|
67
75
|
function getNativeModule(): NativeIOSModule {
|
|
68
|
-
if (Platform.OS !== 'ios') {
|
|
69
|
-
throw new Error(
|
|
76
|
+
if (Platform.OS !== 'ios' && Platform.OS !== 'android') {
|
|
77
|
+
throw new Error(
|
|
78
|
+
'Erxes native messenger is only available on iOS and Android.'
|
|
79
|
+
);
|
|
70
80
|
}
|
|
71
81
|
|
|
72
82
|
if (!nativeModule) {
|