rn-webim-chat
Implementation of webim sdk for react-native
Inspired by volga-volga/react-native-webim
Platforms:
Installation
- Requires React Native version 0.60.0, or later.
- Supports iOS 10.0, or later.
Via NPM
npm install rn-webim-chat
Via Yarn
yarn add rn-webim-chat
📱 iOS (Extra steps)
- add
WebimClientLibrary
to Podfile with specific version (Wrapper was written for v3.37.4) - pod install
see example Podfile
Since the official WebimClientLibrary is written is Swift, you need to have Swift enabled in your iOS project. If you already have any .swift files, you are good to go. Otherwise, create a new empty Swift source file in Xcode, and allow it to create the neccessary bridging header when prompted.
Example
In example folder there is simple workflow how to:
- Start and destroy session
- Resume and Pause session
- Get and Send messages
- Rate operator
- Handle errors
How it looks like you can see here It is achieved with simple UI (just test common methods)
Not init session | Requested messages |
Error getMessages (as session is null) | Error sendMessage (as session is null) |
Also there is another example with chat UI react-native-gifted-chat
Methods
Important: All methods are promise based and can throw exceptions. List of error codes will be provided later as get COMMON for both platform.
Init chat
import { RNWebim } from 'rn-webim-chat';
await RNWebim.initSession(builderParams: SessionBuilderParams)
SessionBuilderParams:
- accountName (required) - name of your account in webim system
- location (required) - name of location. For example "mobile"
- accountJSON - encrypted json with user data. See Start chat with user data
- clearVisitorData - clear visitor data before start chat
- storeHistoryLocally - cache messages in local store
- title - title for chat in webim web panel
- providedAuthorizationToken - user token. Session will not start with wrong token. Read webim documentation
- pushToken - FCM token is enough - but Apple pushes will come through APN, so you are not able to process them in app by default.
- appVersion - version of your Application
- prechat - some additional fields to prechat
Resume session
If you have already initialized a session you should resume it to consume and send messages, get actual information by listeners etc.
NOTE: After that execution operator on web chat will get message that user opens a chat.
import { RNWebim } from 'rn-webim-chat';
await RNWebim.resumeSession()
Pause session
If you have already initialized a session you should resume it to consume and send messages, get actual information by listeners etc. After that execution operator on web chat will get message that user opens a chat.
import { RNWebim } from 'rn-webim-chat';
await RNWebim.pauseSession()
Init events listeners
import { RNWebim, WebimEvents} from 'rn-webim-chat';
const listener = RNWebim.addNewMessageListener(({ msg }) => {
// do something
});
// usubscribe
listener.remove();
// or
const listener2 = RNWebim.addListener(WebimEvents.NEW_MESSAGE, ({ msg }) => {
// do something
});
Supported events (WebimEvents
):
-
WebimEvents.NEW_MESSAGE;
-
WebimEvents.REMOVE_MESSAGE;
-
WebimEvents.EDIT_MESSAGE;
-
WebimEvents.CLEAR_DIALOG;
-
WebimEvents.TOKEN_UPDATED;
-
WebimEvents.ERROR;
-
WebimEvents.STATE;
-
WebimEvents.UNREAD_COUNTER;
-
WebimEvents.TYPING;
-
WebimEvents.FILE_UPLOADING_PROGRESS;
Get messages
As you called getAllMessages
after that you should call nextMessages
as reading "all messages" during the same session will get no result (native implementation uses holder and cursor by last loaded message)
const { messages } = await RNWebim.getLastMessages(limit);
// or
const { messages } = await RNWebim.getNextMessages(limit);
// or
const { messages } = await RNWebim.getAllMessages();
Message type
export type WebimMessage = {
id: string;
serverSideId: string;
avatar?: string;
time: number;
type: MessageTypeAlias; // 'OPERATOR', 'VISITOR', 'INFO', 'ACTION_REQUEST', 'CONTACTS_REQUEST', 'FILE_FROM_OPERATOR', 'FILE_FROM_VISITOR', 'OPERATOR_BUSY', 'KEYBOARD', 'KEYBOARD_RESPONSE';
text: string;
name: string;
status: 'SENT' | 'SENDING';
read: boolean;
canEdit: boolean;
carReply: boolean;
isEdited: boolean;
canReact: boolean;
canChangeReaction: boolean;
visitorReaction?: string;
stickerId?: number;
quote?: Quote;
attachment?: WebimAttachment;
operatorId?: string;
}
Quote type
export type Quote = {
authorId?: string;
senderName: string;
messageId: string;
messageText: string;
messageType: MessageTypeAlias;
state: 'FILLED' | 'NOT_FOUND' | 'PENDING';
timestamp: Date | number;
attachment?: WebimAttachment;
};
Included attachment
export interface WebimAttachment {
contentType: string;
info: string;
name: string;
size: number;
url: string;
}
Note: method getAllMessages
works strange on iOS, and sometimes returns empty array. We recommend to use getLastMessages
instead
Send text message
import RNWebim from 'rn-webim-chat';
const messageId = await RNWebim.send(message);
Read Messages (mark as read)
You can manually mark all messages as read by calling this method.
import RNWebim from 'rn-webim-chat';
await RNWebim.readMessages();
Attach files
Use build in method for file attaching:
In future will add possibility to use external library as react-native-fs
and some other picker to import files via them.
For now there are such methods
Attach file
var result: AttachFileResult = await RNWebim.tryAttachAndSendFile();
console.log('uri: ', result.uri)
console.log('name: ', result.name)
console.log('mime: ', result.mime)
console.log('extension: ', result.extension)
Send file
import RNWebim from 'rn-webim-chat';
try {
RNWebim.sendFile(uri, name, mime, extension)
console.log('Result: ', sendingResult.id)
} catch (e) {
// can throw such errors
'FILE_SIZE_EXCEEDED', 'FILE_SIZE_TOO_SMALL', 'FILE_TYPE_NOT_ALLOWED', 'MAX_FILES_COUNT_PER_CHAT_EXCEEDED', 'UPLOADED_FILE_NOT_FOUND', 'UNAUTHORIZED',
}
Attach and Send file
const onSelectFiles = useCallback(async () => {
try {
const fileResult = await RNWebim.tryAttachAndSendFile();
console.log('File result: ', fileResult);
} catch (err: any) {
const webimError = err as WebimNativeError;
console.log('Chat][File] error: ', webimError);
if (webimError.errorType === 'common') {
setNotFatalError(
webimError.message + `(Code: ${webimError.errorCode})`
);
} else {
setFatalError(webimError.message + `(Code: ${webimError.errorCode})`);
}
}
}, []);
Rate current operator
RNWebim.rateOperator(rate: number)
-
rate
(required) - is number from 1 to 5
Get current operator
import RNWebim from 'rn-webim-chat';
RNWebim.getCurrentOperator()
it returns such object
export type Operator = {
id: string;
name: string;
avatar?: string;
title: string;
info: string;
};
Destroy session
RNWebim.destroySession(clearData);
- clearData (optional) boolean - If true wil
Start chat with user data
Tl;DR; You have to generate private key in your Webim Account and kinda sign your user fields values. For more details see webim documentation for client identification.
in Example app there is code how to achieve it. Example:
I'd recommend to you use some lightweight library. HMAC-256 is enough. Actually you can use md5 algorithm - but I'd avoid it. There are some other aproches e.g. with JsCrypto or with react-native-crypto . But here you need to hash all your modules. Like here. But the choice it is up to you!
- install js-sha256
- write hash-function to sign your fields.
- use it in your app.
// chat-utils.ts file
import { sha256 } from 'js-sha256';
const getHmac_sha256 = async (str: string, privateKey: string) => {
return sha256.hmac(privateKey, str);
};
/**
* Returns hash value for authorized user.
* @param obj - User's json fields.
* @param privateKey - private key value. By that hash will be generated.
*/
export const getHashForChatSign = async (
obj: { [key: string]: string },
privateKey: string
) => {
const keys = Object.keys(obj).sort();
const str = keys.map((key) => obj[key]).join('');
return await getHmac_sha256(str, privateKey);
};
// App.tsx file
...
import { getHashForChatSign } from './chat-utils';
const PRIVATE_KEY = 'YOUR-PRIVATE-KEY-FROM-PORTAL';
const CHAT_SERVICE_ACCOUNT = 'YOU-ACCOUNT';
const acc = {
fields: {
id: 'some-id',
display_name: '1.0.0',
phone: '+79000000000',
address: 'Tomsk',
},
hash: '',
};
async function intSession() {
acc.hash = await getHashForChatSign(acc.fields, PRIVATE_KEY);
const sessionsParams = {
accountName: CHAT_SERVICE_ACCOUNT,
location: '',
storeHistoryLocally: true,
accountJSON: JSON.stringify(acc),
appVersion: AppConfig.version,
clearVisitorData: true,
};
await RNWebim.resumeSession(sessionsParams);
console.log('[Chat][Init] initialized with params: ', sessionsParams);
};
...
Contributing
See the contributing guide guide to learn how to contribute to the repository and the development workflow.
License
Software provided as it is. It will be maintained time-to-time. Currently, I have to use this package in some applications, so I try to keep it on working. If you want to help or improve something see section #Contributing
Made with create-react-native-library