rn-erxes-sdk 0.1.26 → 0.2.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/README.md +62 -235
- package/docs/native-ios.md +170 -0
- package/ios/RnErxesSdk.m +25 -0
- package/ios/RnErxesSdk.swift +189 -0
- package/lib/commonjs/index.js +3 -4
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/nativeIos.js +50 -0
- package/lib/commonjs/nativeIos.js.map +1 -0
- package/lib/module/index.js +1 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/nativeIos.js +43 -0
- package/lib/module/nativeIos.js.map +1 -0
- package/lib/typescript/index.d.ts +2 -1
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/nativeIos.d.ts +23 -0
- package/lib/typescript/nativeIos.d.ts.map +1 -0
- package/package.json +5 -11
- package/rn-erxes-sdk.podspec +45 -0
- package/src/index.tsx +2 -1
- package/src/nativeIos.ts +74 -0
package/README.md
CHANGED
|
@@ -93,275 +93,107 @@ erxes is composed of 2 main components: **XOS** & **Plugins**
|
|
|
93
93
|
|
|
94
94
|
# rn-erxes-sdk
|
|
95
95
|
|
|
96
|
-
A React Native
|
|
96
|
+
A React Native bridge for the native SwiftUI erxes messenger
|
|
97
|
+
([`erxes/erxes-ios-sdk`](https://github.com/erxes/erxes-ios-sdk) `0.30.0`).
|
|
97
98
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
## Installation
|
|
101
|
-
|
|
102
|
-
Install the SDK with Yarn:
|
|
103
|
-
|
|
104
|
-
```bash
|
|
105
|
-
yarn add rn-erxes-sdk
|
|
106
|
-
```
|
|
107
|
-
|
|
108
|
-
or npm:
|
|
109
|
-
|
|
110
|
-
```bash
|
|
111
|
-
npm install --save rn-erxes-sdk
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
```bash
|
|
115
|
-
npm i rn-erxes-sdk
|
|
99
|
+
```tsx
|
|
100
|
+
import { ErxesNativeIOS } from 'rn-erxes-sdk';
|
|
116
101
|
```
|
|
117
102
|
|
|
118
|
-
|
|
103
|
+
## Requirements
|
|
119
104
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
105
|
+
| | |
|
|
106
|
+
|---|---|
|
|
107
|
+
| iOS | 16.0+ |
|
|
108
|
+
| Swift | 5.9+ |
|
|
109
|
+
| React Native | 0.81+ |
|
|
110
|
+
| Expo SDK | 53+ (development build or prebuild — Expo Go not supported) |
|
|
123
111
|
|
|
124
|
-
|
|
125
|
-
npm i rn-erxes-sdk@0.1.26
|
|
126
|
-
```
|
|
112
|
+
## Docs
|
|
127
113
|
|
|
128
|
-
|
|
114
|
+
- [Native iOS guide](docs/native-ios.md)
|
|
129
115
|
|
|
130
|
-
##
|
|
116
|
+
## Installation
|
|
131
117
|
|
|
132
|
-
|
|
118
|
+
### Bare React Native
|
|
133
119
|
|
|
134
120
|
```bash
|
|
135
|
-
|
|
136
|
-
|
|
121
|
+
yarn add rn-erxes-sdk
|
|
122
|
+
cd ios && pod install
|
|
137
123
|
```
|
|
138
124
|
|
|
139
|
-
|
|
125
|
+
### Expo
|
|
140
126
|
|
|
141
127
|
```bash
|
|
142
|
-
npx expo install
|
|
143
|
-
npm install --save react-native-get-random-values
|
|
128
|
+
npx expo install rn-erxes-sdk expo-build-properties
|
|
144
129
|
```
|
|
145
130
|
|
|
146
|
-
|
|
147
|
-
- **`react-native-get-random-values`** — required. The SDK imports it internally to polyfill `crypto.getRandomValues`, which is used to generate a guest visitor id. It must be present in the host app's dependency tree.
|
|
131
|
+
Add to `app.json`:
|
|
148
132
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
133
|
+
```json
|
|
134
|
+
{
|
|
135
|
+
"plugins": [
|
|
136
|
+
["expo-build-properties", { "ios": { "deploymentTarget": "16.0" } }]
|
|
137
|
+
]
|
|
138
|
+
}
|
|
153
139
|
```
|
|
154
140
|
|
|
155
|
-
- **`expo-image-picker`** — optional. If installed, the messenger lets users attach images from their library. The SDK loads it lazily, so the attachment button is simply hidden when it is not installed. (Bare React Native apps may use `react-native-image-picker` instead — it is detected the same way.)
|
|
156
|
-
|
|
157
|
-
## Quick start with Expo
|
|
158
|
-
|
|
159
141
|
```bash
|
|
160
|
-
npx
|
|
161
|
-
cd
|
|
162
|
-
|
|
163
|
-
yarn add rn-erxes-sdk
|
|
164
|
-
npx expo install @react-native-async-storage/async-storage
|
|
165
|
-
yarn add react-native-get-random-values
|
|
166
|
-
|
|
167
|
-
npx expo start --clear
|
|
142
|
+
npx expo prebuild --platform ios
|
|
143
|
+
cd ios && pod install
|
|
144
|
+
npx expo run:ios
|
|
168
145
|
```
|
|
169
146
|
|
|
170
|
-
|
|
147
|
+
## Usage
|
|
171
148
|
|
|
172
|
-
|
|
173
|
-
npm install --save rn-erxes-sdk
|
|
174
|
-
npx expo install @react-native-async-storage/async-storage
|
|
175
|
-
npm install --save react-native-get-random-values
|
|
149
|
+
Call `configure` once at startup. It connects in the background so the messenger opens instantly.
|
|
176
150
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
Render `<ErxesSDK />` from your app entry. In a classic Expo (`blank-typescript`) project that is `App.tsx`. In an Expo Router project the usage commonly lives in:
|
|
151
|
+
```tsx
|
|
152
|
+
import { ErxesNativeIOS } from 'rn-erxes-sdk';
|
|
181
153
|
|
|
182
|
-
|
|
183
|
-
|
|
154
|
+
ErxesNativeIOS.configure({
|
|
155
|
+
integrationId: 'YOUR_INTEGRATION_ID',
|
|
156
|
+
subDomain: 'yourcompany.erxes.io',
|
|
157
|
+
});
|
|
184
158
|
```
|
|
185
159
|
|
|
186
|
-
|
|
160
|
+
Optionally identify the user:
|
|
187
161
|
|
|
188
|
-
```
|
|
189
|
-
|
|
162
|
+
```tsx
|
|
163
|
+
ErxesNativeIOS.setUser({
|
|
164
|
+
email: 'user@example.com',
|
|
165
|
+
name: 'Jane Doe',
|
|
166
|
+
customData: { plan: 'pro' },
|
|
167
|
+
});
|
|
190
168
|
```
|
|
191
169
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
The example below separates three concerns:
|
|
170
|
+
### Option A — Floating launcher (recommended)
|
|
195
171
|
|
|
196
|
-
|
|
197
|
-
2. browser/device/runtime metadata, and
|
|
198
|
-
3. the props passed to `ErxesSDK`.
|
|
172
|
+
Shows a draggable button over your app. Tapping it opens the messenger automatically.
|
|
199
173
|
|
|
200
174
|
```tsx
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
import { ErxesSDK } from 'rn-erxes-sdk';
|
|
204
|
-
|
|
205
|
-
type CurrentUser = {
|
|
206
|
-
firstName?: string;
|
|
207
|
-
lastName?: string;
|
|
208
|
-
primaryEmail?: string;
|
|
209
|
-
primaryPhone?: string;
|
|
210
|
-
sex?: string | number;
|
|
211
|
-
propertiesData?: Record<string, unknown>;
|
|
212
|
-
};
|
|
213
|
-
|
|
214
|
-
type Props = {
|
|
215
|
-
currentUser?: CurrentUser;
|
|
216
|
-
};
|
|
217
|
-
|
|
218
|
-
export default function App({ currentUser }: Props) {
|
|
219
|
-
const integrationId = 'YOUR_INTEGRATION_ID';
|
|
220
|
-
const subDomain = 'YOUR_SUBDOMAIN.next.erxes.io';
|
|
221
|
-
|
|
222
|
-
const data = {
|
|
223
|
-
firstName: currentUser?.firstName ?? '',
|
|
224
|
-
lastName: currentUser?.lastName ?? '',
|
|
225
|
-
primaryEmail: currentUser?.primaryEmail ?? '',
|
|
226
|
-
sex: currentUser?.sex ?? '',
|
|
227
|
-
Type: 'mobile',
|
|
228
|
-
...currentUser?.propertiesData,
|
|
229
|
-
};
|
|
230
|
-
|
|
231
|
-
const properties = {
|
|
232
|
-
remoteAddress: '',
|
|
233
|
-
region: '',
|
|
234
|
-
countryCode: '',
|
|
235
|
-
city: '',
|
|
236
|
-
country: '',
|
|
237
|
-
url: 'https://YOUR_SUBDOMAIN.nextwidgets.erxes.io/',
|
|
238
|
-
hostname: 'YOUR_SUBDOMAIN.nextwidgets.erxes.io',
|
|
239
|
-
language: 'en-US',
|
|
240
|
-
userAgent: Platform.OS,
|
|
241
|
-
};
|
|
242
|
-
|
|
243
|
-
return (
|
|
244
|
-
<View style={{ flex: 1 }}>
|
|
245
|
-
<ErxesSDK
|
|
246
|
-
integrationId={integrationId}
|
|
247
|
-
subDomain={subDomain}
|
|
248
|
-
onBack={() => console.log('onBack')}
|
|
249
|
-
showWidget={false}
|
|
250
|
-
phone={currentUser?.primaryPhone ?? ''}
|
|
251
|
-
data={data}
|
|
252
|
-
properties={properties}
|
|
253
|
-
/>
|
|
254
|
-
</View>
|
|
255
|
-
);
|
|
256
|
-
}
|
|
175
|
+
ErxesNativeIOS.showLauncher();
|
|
176
|
+
// ErxesNativeIOS.hideLauncher(); // to remove it
|
|
257
177
|
```
|
|
258
178
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
- The exact `currentUser` query depends on your host application — the SDK does not provide it.
|
|
262
|
-
- `data` should normally be mapped from the authenticated user's query result rather than hardcoded.
|
|
263
|
-
- Do not hardcode private customer information in production.
|
|
264
|
-
- Empty property values are acceptable when metadata is unavailable.
|
|
265
|
-
- Do not fake IP addresses or location values.
|
|
266
|
-
- Replace `YOUR_INTEGRATION_ID` and `YOUR_SUBDOMAIN` with the values from your erxes environment.
|
|
267
|
-
- `Platform.OS` is only a lightweight fallback for `userAgent`; it is not a complete browser user-agent string.
|
|
179
|
+
### Option B — Your own button
|
|
268
180
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
`data` is customer-profile information. It is forwarded to the erxes `widgetsMessengerConnect` mutation (as the `data` JSON argument) when the SDK connects, and is used to create or identify the customer.
|
|
181
|
+
If you have a custom trigger in your UI, call `showMessenger()` directly:
|
|
272
182
|
|
|
273
183
|
```tsx
|
|
274
|
-
|
|
275
|
-
firstName: currentUser?.firstName ?? '',
|
|
276
|
-
lastName: currentUser?.lastName ?? '',
|
|
277
|
-
primaryEmail: currentUser?.primaryEmail ?? '',
|
|
278
|
-
sex: currentUser?.sex ?? '',
|
|
279
|
-
Type: 'mobile',
|
|
280
|
-
...currentUser?.propertiesData,
|
|
281
|
-
};
|
|
184
|
+
<Button title="Support" onPress={() => ErxesNativeIOS.showMessenger()} />
|
|
282
185
|
```
|
|
283
186
|
|
|
284
|
-
|
|
285
|
-
- Custom fields may be included when relevant (e.g. spread from `propertiesData`).
|
|
286
|
-
- `data` is optional — when omitted, the visitor is connected as a guest.
|
|
287
|
-
- Do not use fake values in production.
|
|
288
|
-
|
|
289
|
-
## Browser and device information
|
|
290
|
-
|
|
291
|
-
`properties` describes the browser, device, and runtime environment. When the SDK has an identified customer, it sends these values to the erxes `widgetsSaveBrowserInfo` mutation internally — **you do not call it yourself**, you only pass the `properties` prop.
|
|
187
|
+
On logout:
|
|
292
188
|
|
|
293
189
|
```tsx
|
|
294
|
-
|
|
295
|
-
remoteAddress: '',
|
|
296
|
-
region: '',
|
|
297
|
-
countryCode: '',
|
|
298
|
-
city: '',
|
|
299
|
-
country: '',
|
|
300
|
-
url: 'https://YOUR_SUBDOMAIN.nextwidgets.erxes.io/',
|
|
301
|
-
hostname: 'YOUR_SUBDOMAIN.nextwidgets.erxes.io',
|
|
302
|
-
language: 'en-US',
|
|
303
|
-
userAgent: 'DEVICE_USER_AGENT',
|
|
304
|
-
};
|
|
305
|
-
```
|
|
306
|
-
|
|
307
|
-
- Empty strings are acceptable when a value is unavailable.
|
|
308
|
-
- Do not fake IP addresses or location values.
|
|
309
|
-
- Collect real runtime values where possible.
|
|
310
|
-
|
|
311
|
-
For reference, the mutation the SDK calls internally is:
|
|
312
|
-
|
|
313
|
-
```graphql
|
|
314
|
-
mutation widgetsSaveBrowserInfo(
|
|
315
|
-
$customerId: String
|
|
316
|
-
$visitorId: String
|
|
317
|
-
$browserInfo: JSON!
|
|
318
|
-
) {
|
|
319
|
-
widgetsSaveBrowserInfo(
|
|
320
|
-
customerId: $customerId
|
|
321
|
-
visitorId: $visitorId
|
|
322
|
-
browserInfo: $browserInfo
|
|
323
|
-
) {
|
|
324
|
-
_id
|
|
325
|
-
conversationId
|
|
326
|
-
customerId
|
|
327
|
-
}
|
|
328
|
-
}
|
|
190
|
+
ErxesNativeIOS.clearUser();
|
|
329
191
|
```
|
|
330
192
|
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
- On first launch the SDK generates a guest **visitor id** (a 24-character hex string) and uses it to connect.
|
|
334
|
-
- After connecting, the resolved **customer id** is cached in `AsyncStorage` and reused on later launches.
|
|
335
|
-
|
|
336
|
-
You only pass the relevant props (`data`, `properties`, `phone`); you should not duplicate this connect / save-browser-info flow yourself.
|
|
337
|
-
|
|
338
|
-
## Props
|
|
339
|
-
|
|
340
|
-
Public props of `ErxesSDK` (from the SDK's TypeScript types):
|
|
341
|
-
|
|
342
|
-
| Prop | Type | Required | Description |
|
|
343
|
-
| --- | --- | --- | --- |
|
|
344
|
-
| `integrationId` | `string` | Yes | erxes messenger integration id used to connect. |
|
|
345
|
-
| `subDomain` | `string` | Yes | erxes environment subdomain (e.g. `YOUR_SUBDOMAIN.next.erxes.io`); used to build the GraphQL/WS endpoints and asset URLs. |
|
|
346
|
-
| `showWidget` | `boolean` | Yes | When `true`, renders the floating launcher button; when `false`, renders the messenger inline. |
|
|
347
|
-
| `brandCode` | `string` | No | Brand code; used as a fallback when `integrationId` is not provided. |
|
|
348
|
-
| `email` | `string` | No | When set, the contact is connected as an identified user (`isUser`). |
|
|
349
|
-
| `onBack` | `() => void` | No | Called when the user navigates back from the messenger. |
|
|
350
|
-
| `phone` | `string` | No | Phone number used to identify the customer on connect. |
|
|
351
|
-
| `data` | `object` | No | Customer-profile data forwarded to `widgetsMessengerConnect`. |
|
|
352
|
-
| `properties` | `object` | No | Browser/device metadata sent as `browserInfo` to `widgetsSaveBrowserInfo`. |
|
|
353
|
-
| `backIcon` | `ImageSource` | No | Custom back icon. |
|
|
354
|
-
| `newChatIcon` | `ImageSource` | No | Custom "new chat" icon. |
|
|
355
|
-
| `sendIcon` | `ImageSource` | No | Custom send icon. |
|
|
193
|
+
Full example: [Native iOS guide](docs/native-ios.md).
|
|
356
194
|
|
|
357
195
|
## Troubleshooting
|
|
358
196
|
|
|
359
|
-
### Clear Expo cache
|
|
360
|
-
|
|
361
|
-
```bash
|
|
362
|
-
npx expo start --clear
|
|
363
|
-
```
|
|
364
|
-
|
|
365
197
|
### Confirm the installed version
|
|
366
198
|
|
|
367
199
|
```bash
|
|
@@ -378,30 +210,25 @@ npm ls rn-erxes-sdk
|
|
|
378
210
|
|
|
379
211
|
```bash
|
|
380
212
|
yarn add rn-erxes-sdk@latest
|
|
381
|
-
npx expo start --clear
|
|
382
213
|
```
|
|
383
214
|
|
|
384
215
|
or:
|
|
385
216
|
|
|
386
217
|
```bash
|
|
387
218
|
npm install --save rn-erxes-sdk@latest
|
|
388
|
-
npx expo start --clear
|
|
389
219
|
```
|
|
390
220
|
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
The required peer dependencies (`@react-native-async-storage/async-storage`, `react-native-get-random-values`) must be installed in the **host app**. The SDK does not bundle them.
|
|
394
|
-
|
|
395
|
-
### `await is not defined` (BSON Metro crash)
|
|
221
|
+
After upgrading, reinstall pods and rebuild the app:
|
|
396
222
|
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
await is not defined
|
|
401
|
-
node_modules/bson/lib/bson.mjs
|
|
223
|
+
```bash
|
|
224
|
+
cd ios
|
|
225
|
+
pod install
|
|
402
226
|
```
|
|
403
227
|
|
|
404
|
-
|
|
228
|
+
### Expo Go
|
|
229
|
+
|
|
230
|
+
This package uses native Swift code and does not run in Expo Go. Use an Expo
|
|
231
|
+
development build or a bare React Native app.
|
|
405
232
|
|
|
406
233
|
## Maintainer workflow
|
|
407
234
|
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
# Native iOS Guide
|
|
2
|
+
|
|
3
|
+
`ErxesNativeIOS` bridges the native SwiftUI erxes messenger
|
|
4
|
+
([`erxes/erxes-ios-sdk`](https://github.com/erxes/erxes-ios-sdk) `0.30.0`)
|
|
5
|
+
into your React Native app.
|
|
6
|
+
|
|
7
|
+
## Requirements
|
|
8
|
+
|
|
9
|
+
| | |
|
|
10
|
+
|---|---|
|
|
11
|
+
| iOS | 16.0+ |
|
|
12
|
+
| Swift | 5.9+ |
|
|
13
|
+
| React Native | 0.81+ |
|
|
14
|
+
| Expo SDK | 53+ (development build or prebuild only — Expo Go not supported) |
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
### Bare React Native
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
yarn add rn-erxes-sdk
|
|
24
|
+
cd ios && pod install
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### Expo
|
|
28
|
+
|
|
29
|
+
Expo Go cannot load custom native modules. You need a development build or prebuild.
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
npx expo install rn-erxes-sdk expo-build-properties
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Set the minimum iOS deployment target in `app.json`:
|
|
36
|
+
|
|
37
|
+
```json
|
|
38
|
+
{
|
|
39
|
+
"plugins": [
|
|
40
|
+
["expo-build-properties", { "ios": { "deploymentTarget": "16.0" } }]
|
|
41
|
+
]
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Prebuild and install pods:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
npx expo prebuild --platform ios
|
|
49
|
+
cd ios && pod install
|
|
50
|
+
npx expo run:ios
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## Setup
|
|
56
|
+
|
|
57
|
+
Call `configure` once at app startup (e.g. inside `useEffect` in your root component). This starts the connection handshake in the background so the messenger is ready instantly when the user opens it.
|
|
58
|
+
|
|
59
|
+
```tsx
|
|
60
|
+
import { ErxesNativeIOS } from 'rn-erxes-sdk';
|
|
61
|
+
|
|
62
|
+
ErxesNativeIOS.configure({
|
|
63
|
+
integrationId: 'YOUR_INTEGRATION_ID',
|
|
64
|
+
subDomain: 'yourcompany.erxes.io',
|
|
65
|
+
});
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
You can pass `endpoint` instead of `subDomain`:
|
|
69
|
+
|
|
70
|
+
```tsx
|
|
71
|
+
ErxesNativeIOS.configure({
|
|
72
|
+
integrationId: 'YOUR_INTEGRATION_ID',
|
|
73
|
+
endpoint: 'https://yourcompany.erxes.io',
|
|
74
|
+
});
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Optionally identify the logged-in user:
|
|
78
|
+
|
|
79
|
+
```tsx
|
|
80
|
+
ErxesNativeIOS.setUser({
|
|
81
|
+
email: 'user@example.com',
|
|
82
|
+
phone: '+15551234567',
|
|
83
|
+
name: 'Jane Doe',
|
|
84
|
+
customData: { plan: 'pro' }, // any key-value pairs
|
|
85
|
+
});
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## Showing the messenger
|
|
91
|
+
|
|
92
|
+
There are two ways to let users open the messenger. Pick one.
|
|
93
|
+
|
|
94
|
+
### Option A — Floating launcher button (recommended)
|
|
95
|
+
|
|
96
|
+
Call `showLauncher()` after `configure()`. A draggable floating button appears on screen automatically once the SDK connects. The user taps it to open the messenger. No extra code needed.
|
|
97
|
+
|
|
98
|
+
```tsx
|
|
99
|
+
ErxesNativeIOS.configure({ integrationId, subDomain });
|
|
100
|
+
ErxesNativeIOS.showLauncher();
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
To remove the launcher (e.g. on certain screens or after logout):
|
|
104
|
+
|
|
105
|
+
```tsx
|
|
106
|
+
ErxesNativeIOS.hideLauncher();
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Option B — Your own button
|
|
110
|
+
|
|
111
|
+
If you have a custom button, tab, or trigger in your own UI, call `showMessenger()` directly. Skip `showLauncher()`.
|
|
112
|
+
|
|
113
|
+
```tsx
|
|
114
|
+
ErxesNativeIOS.configure({ integrationId, subDomain });
|
|
115
|
+
|
|
116
|
+
// somewhere in your UI:
|
|
117
|
+
<Button title="Support" onPress={() => ErxesNativeIOS.showMessenger()} />
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## Logout
|
|
123
|
+
|
|
124
|
+
Clear the user when they log out of your app:
|
|
125
|
+
|
|
126
|
+
```tsx
|
|
127
|
+
ErxesNativeIOS.clearUser();
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## Full example
|
|
133
|
+
|
|
134
|
+
```tsx
|
|
135
|
+
import React, { useEffect } from 'react';
|
|
136
|
+
import { View, Button } from 'react-native';
|
|
137
|
+
import { ErxesNativeIOS } from 'rn-erxes-sdk';
|
|
138
|
+
|
|
139
|
+
export default function App() {
|
|
140
|
+
useEffect(() => {
|
|
141
|
+
ErxesNativeIOS.configure({
|
|
142
|
+
integrationId: 'YOUR_INTEGRATION_ID',
|
|
143
|
+
subDomain: 'yourcompany.erxes.io',
|
|
144
|
+
primaryColor: '#3f78d9',
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
ErxesNativeIOS.setUser({
|
|
148
|
+
email: 'user@example.com',
|
|
149
|
+
name: 'Jane Doe',
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
// Show floating launcher — remove this if you use your own button instead
|
|
153
|
+
ErxesNativeIOS.showLauncher();
|
|
154
|
+
}, []);
|
|
155
|
+
|
|
156
|
+
return <View style={{ flex: 1 }} />;
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## Troubleshooting
|
|
163
|
+
|
|
164
|
+
**Native module not found** — run `pod install` and rebuild:
|
|
165
|
+
```bash
|
|
166
|
+
cd ios && pod install
|
|
167
|
+
npx react-native run-ios # or: npx expo run:ios
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
**Expo Go** — not supported. Build a development client with `npx expo run:ios`.
|
package/ios/RnErxesSdk.m
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
#import <React/RCTBridgeModule.h>
|
|
2
|
+
|
|
3
|
+
@interface RCT_EXTERN_MODULE(RnErxesSdk, NSObject)
|
|
4
|
+
|
|
5
|
+
RCT_EXTERN_METHOD(configure:(NSDictionary *)options
|
|
6
|
+
resolver:(RCTPromiseResolveBlock)resolve
|
|
7
|
+
rejecter:(RCTPromiseRejectBlock)reject)
|
|
8
|
+
|
|
9
|
+
RCT_EXTERN_METHOD(setUser:(NSDictionary *)options
|
|
10
|
+
resolver:(RCTPromiseResolveBlock)resolve
|
|
11
|
+
rejecter:(RCTPromiseRejectBlock)reject)
|
|
12
|
+
|
|
13
|
+
RCT_EXTERN_METHOD(clearUser:(RCTPromiseResolveBlock)resolve
|
|
14
|
+
rejecter:(RCTPromiseRejectBlock)reject)
|
|
15
|
+
|
|
16
|
+
RCT_EXTERN_METHOD(showMessenger:(RCTPromiseResolveBlock)resolve
|
|
17
|
+
rejecter:(RCTPromiseRejectBlock)reject)
|
|
18
|
+
|
|
19
|
+
RCT_EXTERN_METHOD(showLauncher:(RCTPromiseResolveBlock)resolve
|
|
20
|
+
rejecter:(RCTPromiseRejectBlock)reject)
|
|
21
|
+
|
|
22
|
+
RCT_EXTERN_METHOD(hideLauncher:(RCTPromiseResolveBlock)resolve
|
|
23
|
+
rejecter:(RCTPromiseRejectBlock)reject)
|
|
24
|
+
|
|
25
|
+
@end
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
import MessengerSDK
|
|
3
|
+
import UIKit
|
|
4
|
+
import React
|
|
5
|
+
|
|
6
|
+
@objc(RnErxesSdk)
|
|
7
|
+
final class RnErxesSdk: NSObject {
|
|
8
|
+
@objc
|
|
9
|
+
static func requiresMainQueueSetup() -> Bool {
|
|
10
|
+
true
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
@objc(configure:resolver:rejecter:)
|
|
14
|
+
func configure(
|
|
15
|
+
_ options: NSDictionary,
|
|
16
|
+
resolver resolve: @escaping RCTPromiseResolveBlock,
|
|
17
|
+
rejecter reject: @escaping RCTPromiseRejectBlock
|
|
18
|
+
) {
|
|
19
|
+
Task { @MainActor in
|
|
20
|
+
guard let integrationId = options["integrationId"] as? String, !integrationId.isEmpty else {
|
|
21
|
+
reject("missing_integration_id", "integrationId is required", nil)
|
|
22
|
+
return
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
guard let endpoint = Self.endpoint(from: options) else {
|
|
26
|
+
reject("missing_endpoint", "endpoint, serverUrl, or subDomain is required", nil)
|
|
27
|
+
return
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
let cachedCustomerId = Self.string(options["cachedCustomerId"])
|
|
31
|
+
|
|
32
|
+
MessengerSDK.configure(
|
|
33
|
+
MessengerConfig(
|
|
34
|
+
endpoint: endpoint,
|
|
35
|
+
integrationId: integrationId,
|
|
36
|
+
cachedCustomerId: cachedCustomerId
|
|
37
|
+
)
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
resolve(nil)
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
@objc(setUser:resolver:rejecter:)
|
|
45
|
+
func setUser(
|
|
46
|
+
_ options: NSDictionary,
|
|
47
|
+
resolver resolve: @escaping RCTPromiseResolveBlock,
|
|
48
|
+
rejecter reject: @escaping RCTPromiseRejectBlock
|
|
49
|
+
) {
|
|
50
|
+
Task { @MainActor in
|
|
51
|
+
let email = Self.string(options["email"])
|
|
52
|
+
let phone = Self.string(options["phone"])
|
|
53
|
+
let name = Self.string(options["name"])
|
|
54
|
+
let customData = Self.stringDictionary(options["customData"])
|
|
55
|
+
|
|
56
|
+
MessengerSDK.setUser(
|
|
57
|
+
MessengerUser(
|
|
58
|
+
email: email,
|
|
59
|
+
phone: phone,
|
|
60
|
+
name: name,
|
|
61
|
+
customData: customData
|
|
62
|
+
)
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
resolve(nil)
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
@objc(clearUser:rejecter:)
|
|
70
|
+
func clearUser(
|
|
71
|
+
_ resolve: @escaping RCTPromiseResolveBlock,
|
|
72
|
+
rejecter reject: @escaping RCTPromiseRejectBlock
|
|
73
|
+
) {
|
|
74
|
+
Task { @MainActor in
|
|
75
|
+
MessengerSDK.clearUser()
|
|
76
|
+
resolve(nil)
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
@objc(showMessenger:rejecter:)
|
|
81
|
+
func showMessenger(
|
|
82
|
+
_ resolve: @escaping RCTPromiseResolveBlock,
|
|
83
|
+
rejecter reject: @escaping RCTPromiseRejectBlock
|
|
84
|
+
) {
|
|
85
|
+
Task { @MainActor in
|
|
86
|
+
guard let presenter = Self.topViewController() else {
|
|
87
|
+
reject("missing_presenter", "Unable to find a view controller to present from", nil)
|
|
88
|
+
return
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
MessengerSDK.showMessenger(from: presenter)
|
|
92
|
+
resolve(nil)
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
@objc(showLauncher:rejecter:)
|
|
97
|
+
func showLauncher(
|
|
98
|
+
_ resolve: @escaping RCTPromiseResolveBlock,
|
|
99
|
+
rejecter reject: @escaping RCTPromiseRejectBlock
|
|
100
|
+
) {
|
|
101
|
+
Task { @MainActor in
|
|
102
|
+
MessengerSDK.showLauncher()
|
|
103
|
+
resolve(nil)
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
@objc(hideLauncher:rejecter:)
|
|
108
|
+
func hideLauncher(
|
|
109
|
+
_ resolve: @escaping RCTPromiseResolveBlock,
|
|
110
|
+
rejecter reject: @escaping RCTPromiseRejectBlock
|
|
111
|
+
) {
|
|
112
|
+
Task { @MainActor in
|
|
113
|
+
MessengerSDK.hideLauncher()
|
|
114
|
+
resolve(nil)
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
private static func endpoint(from options: NSDictionary) -> String? {
|
|
119
|
+
if let endpoint = string(options["endpoint"]) ?? string(options["serverUrl"]) {
|
|
120
|
+
return endpoint
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
guard let subDomain = string(options["subDomain"]) else {
|
|
124
|
+
return nil
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if subDomain.hasPrefix("http://") || subDomain.hasPrefix("https://") {
|
|
128
|
+
return subDomain
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return "https://\(subDomain)"
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
private static func string(_ value: Any?) -> String? {
|
|
135
|
+
guard let value else { return nil }
|
|
136
|
+
|
|
137
|
+
if let value = value as? String {
|
|
138
|
+
return value.isEmpty ? nil : value
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
if let value = value as? NSNumber {
|
|
142
|
+
return value.stringValue
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return nil
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
private static func stringDictionary(_ value: Any?) -> [String: String] {
|
|
149
|
+
guard let dictionary = value as? [String: Any] else {
|
|
150
|
+
return [:]
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return dictionary.reduce(into: [String: String]()) { result, item in
|
|
154
|
+
if let stringValue = string(item.value) {
|
|
155
|
+
result[item.key] = stringValue
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
@MainActor
|
|
161
|
+
private static func topViewController() -> UIViewController? {
|
|
162
|
+
topViewController(from: keyWindow()?.rootViewController)
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
@MainActor
|
|
166
|
+
private static func topViewController(from root: UIViewController?) -> UIViewController? {
|
|
167
|
+
if let navigation = root as? UINavigationController {
|
|
168
|
+
return topViewController(from: navigation.visibleViewController)
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if let tab = root as? UITabBarController {
|
|
172
|
+
return topViewController(from: tab.selectedViewController)
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if let presented = root?.presentedViewController {
|
|
176
|
+
return topViewController(from: presented)
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
return root
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
@MainActor
|
|
183
|
+
private static func keyWindow() -> UIWindow? {
|
|
184
|
+
UIApplication.shared.connectedScenes
|
|
185
|
+
.compactMap { $0 as? UIWindowScene }
|
|
186
|
+
.flatMap(\.windows)
|
|
187
|
+
.first { $0.isKeyWindow }
|
|
188
|
+
}
|
|
189
|
+
}
|
package/lib/commonjs/index.js
CHANGED
|
@@ -3,12 +3,11 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
Object.defineProperty(exports, "
|
|
6
|
+
Object.defineProperty(exports, "ErxesNativeIOS", {
|
|
7
7
|
enumerable: true,
|
|
8
8
|
get: function () {
|
|
9
|
-
return
|
|
9
|
+
return _nativeIos.ErxesNativeIOS;
|
|
10
10
|
}
|
|
11
11
|
});
|
|
12
|
-
var
|
|
13
|
-
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
12
|
+
var _nativeIos = require("./nativeIos");
|
|
14
13
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["
|
|
1
|
+
{"version":3,"names":["_nativeIos","require"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;;;;;;;;;;AAAA,IAAAA,UAAA,GAAAC,OAAA"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.ErxesNativeIOS = void 0;
|
|
7
|
+
var _reactNative = require("react-native");
|
|
8
|
+
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.";
|
|
9
|
+
const nativeModule = _reactNative.NativeModules.RnErxesSdk;
|
|
10
|
+
function getNativeModule() {
|
|
11
|
+
if (_reactNative.Platform.OS !== 'ios') {
|
|
12
|
+
throw new Error('Erxes native messenger is only available on iOS.');
|
|
13
|
+
}
|
|
14
|
+
if (!nativeModule) {
|
|
15
|
+
throw new Error(LINKING_ERROR);
|
|
16
|
+
}
|
|
17
|
+
return nativeModule;
|
|
18
|
+
}
|
|
19
|
+
const ErxesNativeIOS = {
|
|
20
|
+
configure(options) {
|
|
21
|
+
return getNativeModule().configure(options);
|
|
22
|
+
},
|
|
23
|
+
setUser(options) {
|
|
24
|
+
const customData = Object.fromEntries(Object.entries(options.customData ?? {}).filter(_ref => {
|
|
25
|
+
let [, value] = _ref;
|
|
26
|
+
return value !== null && value !== undefined;
|
|
27
|
+
}).map(_ref2 => {
|
|
28
|
+
let [key, value] = _ref2;
|
|
29
|
+
return [key, String(value)];
|
|
30
|
+
}));
|
|
31
|
+
return getNativeModule().setUser({
|
|
32
|
+
...options,
|
|
33
|
+
customData
|
|
34
|
+
});
|
|
35
|
+
},
|
|
36
|
+
clearUser() {
|
|
37
|
+
return getNativeModule().clearUser();
|
|
38
|
+
},
|
|
39
|
+
showMessenger() {
|
|
40
|
+
return getNativeModule().showMessenger();
|
|
41
|
+
},
|
|
42
|
+
showLauncher() {
|
|
43
|
+
return getNativeModule().showLauncher();
|
|
44
|
+
},
|
|
45
|
+
hideLauncher() {
|
|
46
|
+
return getNativeModule().hideLauncher();
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
exports.ErxesNativeIOS = ErxesNativeIOS;
|
|
50
|
+
//# sourceMappingURL=nativeIos.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["_reactNative","require","LINKING_ERROR","nativeModule","NativeModules","RnErxesSdk","getNativeModule","Platform","OS","Error","ErxesNativeIOS","configure","options","setUser","customData","Object","fromEntries","entries","filter","_ref","value","undefined","map","_ref2","key","String","clearUser","showMessenger","showLauncher","hideLauncher","exports"],"sourceRoot":"../../src","sources":["nativeIos.ts"],"mappings":";;;;;;AAAA,IAAAA,YAAA,GAAAC,OAAA;AA0BA,MAAMC,aAAa,GACjB,sHAAsH;AAExH,MAAMC,YAAY,GAAGC,0BAAa,CAACC,UAAyC;AAE5E,SAASC,eAAeA,CAAA,EAAoB;EAC1C,IAAIC,qBAAQ,CAACC,EAAE,KAAK,KAAK,EAAE;IACzB,MAAM,IAAIC,KAAK,CAAC,kDAAkD,CAAC;EACrE;EAEA,IAAI,CAACN,YAAY,EAAE;IACjB,MAAM,IAAIM,KAAK,CAACP,aAAa,CAAC;EAChC;EAEA,OAAOC,YAAY;AACrB;AAEO,MAAMO,cAAc,GAAG;EAC5BC,SAASA,CAACC,OAAwB,EAAE;IAClC,OAAON,eAAe,CAAC,CAAC,CAACK,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,OAAOd,eAAe,CAAC,CAAC,CAACO,OAAO,CAAC;MAC/B,GAAGD,OAAO;MACVE;IACF,CAAC,CAAC;EACJ,CAAC;EACDY,SAASA,CAAA,EAAG;IACV,OAAOpB,eAAe,CAAC,CAAC,CAACoB,SAAS,CAAC,CAAC;EACtC,CAAC;EACDC,aAAaA,CAAA,EAAG;IACd,OAAOrB,eAAe,CAAC,CAAC,CAACqB,aAAa,CAAC,CAAC;EAC1C,CAAC;EACDC,YAAYA,CAAA,EAAG;IACb,OAAOtB,eAAe,CAAC,CAAC,CAACsB,YAAY,CAAC,CAAC;EACzC,CAAC;EACDC,YAAYA,CAAA,EAAG;IACb,OAAOvB,eAAe,CAAC,CAAC,CAACuB,YAAY,CAAC,CAAC;EACzC;AACF,CAAC;AAACC,OAAA,CAAApB,cAAA,GAAAA,cAAA"}
|
package/lib/module/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { ErxesNativeIOS } from './nativeIos';
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
package/lib/module/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["
|
|
1
|
+
{"version":3,"names":["ErxesNativeIOS"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":"AAAA,SAASA,cAAc,QAAQ,aAAa"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { NativeModules, Platform } from 'react-native';
|
|
2
|
+
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.";
|
|
3
|
+
const nativeModule = NativeModules.RnErxesSdk;
|
|
4
|
+
function getNativeModule() {
|
|
5
|
+
if (Platform.OS !== 'ios') {
|
|
6
|
+
throw new Error('Erxes native messenger is only available on iOS.');
|
|
7
|
+
}
|
|
8
|
+
if (!nativeModule) {
|
|
9
|
+
throw new Error(LINKING_ERROR);
|
|
10
|
+
}
|
|
11
|
+
return nativeModule;
|
|
12
|
+
}
|
|
13
|
+
export const ErxesNativeIOS = {
|
|
14
|
+
configure(options) {
|
|
15
|
+
return getNativeModule().configure(options);
|
|
16
|
+
},
|
|
17
|
+
setUser(options) {
|
|
18
|
+
const customData = Object.fromEntries(Object.entries(options.customData ?? {}).filter(_ref => {
|
|
19
|
+
let [, value] = _ref;
|
|
20
|
+
return value !== null && value !== undefined;
|
|
21
|
+
}).map(_ref2 => {
|
|
22
|
+
let [key, value] = _ref2;
|
|
23
|
+
return [key, String(value)];
|
|
24
|
+
}));
|
|
25
|
+
return getNativeModule().setUser({
|
|
26
|
+
...options,
|
|
27
|
+
customData
|
|
28
|
+
});
|
|
29
|
+
},
|
|
30
|
+
clearUser() {
|
|
31
|
+
return getNativeModule().clearUser();
|
|
32
|
+
},
|
|
33
|
+
showMessenger() {
|
|
34
|
+
return getNativeModule().showMessenger();
|
|
35
|
+
},
|
|
36
|
+
showLauncher() {
|
|
37
|
+
return getNativeModule().showLauncher();
|
|
38
|
+
},
|
|
39
|
+
hideLauncher() {
|
|
40
|
+
return getNativeModule().hideLauncher();
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
//# sourceMappingURL=nativeIos.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["NativeModules","Platform","LINKING_ERROR","nativeModule","RnErxesSdk","getNativeModule","OS","Error","ErxesNativeIOS","configure","options","setUser","customData","Object","fromEntries","entries","filter","_ref","value","undefined","map","_ref2","key","String","clearUser","showMessenger","showLauncher","hideLauncher"],"sourceRoot":"../../src","sources":["nativeIos.ts"],"mappings":"AAAA,SAASA,aAAa,EAAEC,QAAQ,QAAQ,cAAc;AA0BtD,MAAMC,aAAa,GACjB,sHAAsH;AAExH,MAAMC,YAAY,GAAGH,aAAa,CAACI,UAAyC;AAE5E,SAASC,eAAeA,CAAA,EAAoB;EAC1C,IAAIJ,QAAQ,CAACK,EAAE,KAAK,KAAK,EAAE;IACzB,MAAM,IAAIC,KAAK,CAAC,kDAAkD,CAAC;EACrE;EAEA,IAAI,CAACJ,YAAY,EAAE;IACjB,MAAM,IAAII,KAAK,CAACL,aAAa,CAAC;EAChC;EAEA,OAAOC,YAAY;AACrB;AAEA,OAAO,MAAMK,cAAc,GAAG;EAC5BC,SAASA,CAACC,OAAwB,EAAE;IAClC,OAAOL,eAAe,CAAC,CAAC,CAACI,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,OAAOb,eAAe,CAAC,CAAC,CAACM,OAAO,CAAC;MAC/B,GAAGD,OAAO;MACVE;IACF,CAAC,CAAC;EACJ,CAAC;EACDY,SAASA,CAAA,EAAG;IACV,OAAOnB,eAAe,CAAC,CAAC,CAACmB,SAAS,CAAC,CAAC;EACtC,CAAC;EACDC,aAAaA,CAAA,EAAG;IACd,OAAOpB,eAAe,CAAC,CAAC,CAACoB,aAAa,CAAC,CAAC;EAC1C,CAAC;EACDC,YAAYA,CAAA,EAAG;IACb,OAAOrB,eAAe,CAAC,CAAC,CAACqB,YAAY,CAAC,CAAC;EACzC,CAAC;EACDC,YAAYA,CAAA,EAAG;IACb,OAAOtB,eAAe,CAAC,CAAC,CAACsB,YAAY,CAAC,CAAC;EACzC;AACF,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,YAAY,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
type NativeIOSConfig = {
|
|
2
|
+
integrationId: string;
|
|
3
|
+
endpoint?: string;
|
|
4
|
+
serverUrl?: string;
|
|
5
|
+
subDomain?: string;
|
|
6
|
+
cachedCustomerId?: string;
|
|
7
|
+
};
|
|
8
|
+
type NativeIOSUser = {
|
|
9
|
+
email?: string;
|
|
10
|
+
phone?: string;
|
|
11
|
+
name?: string;
|
|
12
|
+
customData?: Record<string, string | number | boolean | null | undefined>;
|
|
13
|
+
};
|
|
14
|
+
export declare const ErxesNativeIOS: {
|
|
15
|
+
configure(options: NativeIOSConfig): Promise<void>;
|
|
16
|
+
setUser(options: NativeIOSUser): Promise<void>;
|
|
17
|
+
clearUser(): Promise<void>;
|
|
18
|
+
showMessenger(): Promise<void>;
|
|
19
|
+
showLauncher(): Promise<void>;
|
|
20
|
+
hideLauncher(): Promise<void>;
|
|
21
|
+
};
|
|
22
|
+
export type { NativeIOSConfig, NativeIOSUser };
|
|
23
|
+
//# sourceMappingURL=nativeIos.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nativeIos.d.ts","sourceRoot":"","sources":["../../src/nativeIos.ts"],"names":[],"mappings":"AAEA,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;CAC3B,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;AA4BF,eAAO,MAAM,cAAc;uBACN,eAAe;qBAGjB,aAAa;;;;;CAwB/B,CAAC;AAEF,YAAY,EAAE,eAAe,EAAE,aAAa,EAAE,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rn-erxes-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "react-native erxes sdk",
|
|
5
5
|
"main": "lib/commonjs/index",
|
|
6
6
|
"module": "lib/module/index",
|
|
@@ -10,8 +10,10 @@
|
|
|
10
10
|
"files": [
|
|
11
11
|
"src",
|
|
12
12
|
"lib",
|
|
13
|
+
"docs",
|
|
13
14
|
"android",
|
|
14
|
-
"ios",
|
|
15
|
+
"ios/RnErxesSdk.m",
|
|
16
|
+
"ios/RnErxesSdk.swift",
|
|
15
17
|
"cpp",
|
|
16
18
|
"*.podspec",
|
|
17
19
|
"!lib/typescript/example",
|
|
@@ -81,16 +83,8 @@
|
|
|
81
83
|
"typescript": "^4.5.2"
|
|
82
84
|
},
|
|
83
85
|
"peerDependencies": {
|
|
84
|
-
"@react-native-async-storage/async-storage": ">=2.2.0",
|
|
85
86
|
"react": "*",
|
|
86
|
-
"react-native": "*"
|
|
87
|
-
"react-native-get-random-values": ">=1.11.0",
|
|
88
|
-
"expo-image-picker": "*"
|
|
89
|
-
},
|
|
90
|
-
"peerDependenciesMeta": {
|
|
91
|
-
"expo-image-picker": {
|
|
92
|
-
"optional": true
|
|
93
|
-
}
|
|
87
|
+
"react-native": "*"
|
|
94
88
|
},
|
|
95
89
|
"engines": {
|
|
96
90
|
"node": ">=20.19.0"
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
require 'json'
|
|
2
|
+
|
|
3
|
+
package = JSON.parse(File.read(File.join(__dir__, 'package.json')))
|
|
4
|
+
|
|
5
|
+
begin
|
|
6
|
+
react_native_pods = Pod::Executable.execute_command(
|
|
7
|
+
'node',
|
|
8
|
+
[
|
|
9
|
+
'-p',
|
|
10
|
+
'require.resolve("react-native/scripts/react_native_pods.rb", {paths: [process.argv[1]]})',
|
|
11
|
+
__dir__
|
|
12
|
+
]
|
|
13
|
+
).strip
|
|
14
|
+
require react_native_pods
|
|
15
|
+
rescue StandardError
|
|
16
|
+
# React Native Podfiles normally load react_native_pods.rb before evaluating
|
|
17
|
+
# package podspecs. This fallback keeps podspec parsing useful in isolation.
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
Pod::Spec.new do |s|
|
|
21
|
+
s.name = 'rn-erxes-sdk'
|
|
22
|
+
s.version = package['version']
|
|
23
|
+
s.summary = package['description']
|
|
24
|
+
s.description = package['description']
|
|
25
|
+
s.homepage = package['homepage']
|
|
26
|
+
s.license = package['license']
|
|
27
|
+
s.author = package['author']
|
|
28
|
+
s.platforms = { :ios => '16.0' }
|
|
29
|
+
s.source = { :git => 'https://github.com/erxes/rn-erxes-sdk.git', :tag => "v#{s.version}" }
|
|
30
|
+
s.source_files = 'ios/RnErxesSdk.{m,swift}'
|
|
31
|
+
s.swift_version = '5.9'
|
|
32
|
+
|
|
33
|
+
s.dependency 'React-Core'
|
|
34
|
+
|
|
35
|
+
if defined?(spm_dependency)
|
|
36
|
+
spm_dependency(
|
|
37
|
+
s,
|
|
38
|
+
url: 'https://github.com/Munkhorgilb/ios-sdk.git',
|
|
39
|
+
requirement: { :kind => 'exactVersion', :version => '0.30.0' },
|
|
40
|
+
products: ['MessengerSDK']
|
|
41
|
+
)
|
|
42
|
+
else
|
|
43
|
+
raise 'rn-erxes-sdk requires React Native 0.81+ CocoaPods SPM support to install MessengerSDK 0.0.1'
|
|
44
|
+
end
|
|
45
|
+
end
|
package/src/index.tsx
CHANGED
|
@@ -1 +1,2 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { ErxesNativeIOS } from './nativeIos';
|
|
2
|
+
export type { NativeIOSConfig, NativeIOSUser } from './nativeIos';
|
package/src/nativeIos.ts
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { NativeModules, Platform } from 'react-native';
|
|
2
|
+
|
|
3
|
+
type NativeIOSConfig = {
|
|
4
|
+
integrationId: string;
|
|
5
|
+
endpoint?: string;
|
|
6
|
+
serverUrl?: string;
|
|
7
|
+
subDomain?: string;
|
|
8
|
+
cachedCustomerId?: string;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
type NativeIOSUser = {
|
|
12
|
+
email?: string;
|
|
13
|
+
phone?: string;
|
|
14
|
+
name?: string;
|
|
15
|
+
customData?: Record<string, string | number | boolean | null | undefined>;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
type NativeIOSModule = {
|
|
19
|
+
configure(options: NativeIOSConfig): Promise<void>;
|
|
20
|
+
setUser(options: NativeIOSUser): Promise<void>;
|
|
21
|
+
clearUser(): Promise<void>;
|
|
22
|
+
showMessenger(): Promise<void>;
|
|
23
|
+
showLauncher(): Promise<void>;
|
|
24
|
+
hideLauncher(): Promise<void>;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const LINKING_ERROR =
|
|
28
|
+
"The rn-erxes-sdk native iOS module is not linked. Run `pod install` in your app's ios directory and rebuild the app.";
|
|
29
|
+
|
|
30
|
+
const nativeModule = NativeModules.RnErxesSdk as NativeIOSModule | undefined;
|
|
31
|
+
|
|
32
|
+
function getNativeModule(): NativeIOSModule {
|
|
33
|
+
if (Platform.OS !== 'ios') {
|
|
34
|
+
throw new Error('Erxes native messenger is only available on iOS.');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (!nativeModule) {
|
|
38
|
+
throw new Error(LINKING_ERROR);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return nativeModule;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export const ErxesNativeIOS = {
|
|
45
|
+
configure(options: NativeIOSConfig) {
|
|
46
|
+
return getNativeModule().configure(options);
|
|
47
|
+
},
|
|
48
|
+
setUser(options: NativeIOSUser) {
|
|
49
|
+
const customData = Object.fromEntries(
|
|
50
|
+
Object.entries(options.customData ?? {})
|
|
51
|
+
.filter(([, value]) => value !== null && value !== undefined)
|
|
52
|
+
.map(([key, value]) => [key, String(value)])
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
return getNativeModule().setUser({
|
|
56
|
+
...options,
|
|
57
|
+
customData,
|
|
58
|
+
});
|
|
59
|
+
},
|
|
60
|
+
clearUser() {
|
|
61
|
+
return getNativeModule().clearUser();
|
|
62
|
+
},
|
|
63
|
+
showMessenger() {
|
|
64
|
+
return getNativeModule().showMessenger();
|
|
65
|
+
},
|
|
66
|
+
showLauncher() {
|
|
67
|
+
return getNativeModule().showLauncher();
|
|
68
|
+
},
|
|
69
|
+
hideLauncher() {
|
|
70
|
+
return getNativeModule().hideLauncher();
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
export type { NativeIOSConfig, NativeIOSUser };
|