rn-webim-chat

Webim chat wrapper for React-Native. Supports Android and iOS. Fixed issues for native platforms build that are present in the official package.


Keywords
react-native, ios, android, webim, chat, webim-chat
License
MIT
Install
npm install rn-webim-chat@1.0.0

Documentation

rn-webim-chat

Implementation of webim sdk for react-native

Inspired by volga-volga/react-native-webim

Package publish NPM version npm


Platforms:

React Native

Android

iOS

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