amazon-connect / amazon-connect-chatjs

Amazon Connect ChatJS - a browser-based contact center integration API for Chat on the Agent and Customer side.
https://docs.aws.amazon.com/connect/latest/adminguide/what-is-amazon-connect.html
Apache License 2.0
93 stars 53 forks source link

Support for React Native applications #42

Closed jospas closed 1 year ago

jospas commented 3 years ago

I building out a React Native chat demo using Expo I found that everything worked right up until receiving messages back down the web-socket when running on Android.

The exact same code worked fine using webpack or via remote debugging (actually runs inside Chrome) so I assume there is a window dependency or perhaps other web-socket browser dependency breaking the use of this library in React Native projects

I dropped back to using raw web-sockets and the participant API with no problems, it just would have been nice to use chat-js

Josh

S1rFrancis commented 3 years ago

I am also experiencing the same issue, this library does not work on an Android react native app unless the dev tools are running.

cbettridgehs commented 3 years ago

Ive also hit this issue in my react native app on Android. It appears the connection is being setup but onMessage is not being triggered.

johnmryan commented 3 years ago

Thanks all, will look into this. @jospas , do you know if you get any error logs running it on mobile?

jospas commented 3 years ago

This one is a true Heisenbug, if you enable debugging to get logs it actually runs the component in the browser locally when using Expo then the issue goes away as the web socket support in the browser is used.

klozano commented 2 years ago

Any news on this? I'm facing with the same issue related to the socket

ocho-cesar commented 2 years ago

I'm not being able to use it on iOS either. But by using Expo web, it works.

The only error I see in both environments is

Error while converting argument to string, constructor {
  "data": Object {
    "InitialContactId": "XXX",
    "NextToken": "",
    "Transcript": Array [],
  },
  "error": null,
  "httpResponse": constructor {
    "_abortCallback": [Function o],
    "body": Object {
      "data": Array [
          …

amazon-connect-websocket-manager update would be needed or custom websocketManager implementation

In order to make this library compatible with RN, the Amazon Connect team would need to update the library: https://github.com/amazon-connect/amazon-connect-streams/blob/master/src/lib/amazon-connect-websocket-manager.js I didn't found any source code for this so it's hard for me to give any suggestions.

But I also found that ChatSession.create can accept a websocketManager object, so a custom implementation could be done, a larger digging would be needed in order to know the methods needed.

spencerlepine commented 1 year ago

Hello all,

Reaching out with update for ChatJS support in React Native. The v1.5.0 release included updates to WebSocketManager to unblock this issue.

Install amazon-connect-chatjs@^1.5.0 and refer the ReactNativeSupport.md documentation.

How to use:

Additional configuration can now be passed to setGlobalConfig, which is passed down to WebSocketManager:

const customNetworkStatusUtil = () => {
  if (navigator && navigator.hasOwnProperty("onLine")) {
    return navigator.onLine;
  }

  return true;
}

connect.ChatSession.setGlobalConfig({
  loggerConfig: { /* ... */ },
  // ...
  webSocketManagerConfig: {
    isNetworkOnline: customNetworkStatusUtil,
  }
});

Example Application

For reference, team has also released a React Native + ChatJS Expo demo application.

Notes

This was true heisenbug as mentioned above. With latest updates, there are options to configure new network health checks, monitoring if the device is online (and if websockets are still connected). Since React Native is using different Javascript runtimes [ref], debugging mode seems to use V8 engine (which supports netinfo).

It is difficult to debug amazon-connect-websocket-manager.js bundle file since it was minified, which was the root problem.


Thanks, Spencer

jospas commented 1 year ago

@spencerlepine this is a great addition thank you! I haven't tested as yet, can you describe how this fixes the issue of no websocket implementation being present in native (non-debug deployments) or is this still pending?

I can see the additional configuration really just tunes the websocket manager to detect lack of websocket support or connectivity:

https://github.com/amazon-connect/amazon-connect-chat-ui-examples/blob/8efb93cf53fd339cde71b3830e07f86bd538edaf/connectReactNativeChat/src/components/ChatWrapper.js#L14

What was the work around if you got websockets running in native?

spencerlepine commented 1 year ago

@jospas The work around was providing a way to pass down the network status native to each device/environment, since WebSocketManager was using a browser-only method to check.

Here are more details about root cause:

WebSocketManager will initialize + establish connection, checking bool value of navigator.onLine. When Hermes of JavaScriptCore engine is used, navigator.onLine was undefined- and WebSocketManager would think the device wasn't connected. Debugging in ReactNative seems to be running V8 Javascript engine, which supported window.navigator.

There is also a heartbeat every 250ms, but this logic wasn't reached previously.

Screenshot 2023-04-18 at 12 25 37 PM

First, to unblock non-browser environment, the function needed to ignore undefined navigator.onLine:

const customNetworkStatusUtil = () => {
  if (navigator && navigator.hasOwnProperty("onLine")) {
    return navigator.onLine;
  }

  return true;
}

connect.ChatSession.setGlobalConfig({
  webSocketManagerConfig: {
    isNetworkOnline: customNetworkStatusUtil,
  }
});

WebSocketManager still should have know the true device network status - not just the true override.

To achieve this, there are ReactNative network status checks that can be done, native to the device [ref]:

import ChatSession from "./ChatSession";
import NetInfo from "@react-native-community/netinfo";
import "amazon-connect-chatjs"; // ^1.5.0 - imports global "connect" object 

let isOnline = true;

/** 
 * By default, `isNetworkOnline` will be invoked every 250ms
 * Should only current status, and not make `NetInfo.fetch()` call
 * 
 * @return {boolean} returns true if currently connected to network
*/
const customNetworkStatusUtil = () => isOnline;

const ReactNativeChatComponent = (props) => {

  /** 
   * Network event listener native to device
   * Will update `isOnline` value asynchronously whenever network calls are made
  */
  const unsubscribeNetworkEventListener = NetInfo.addEventListener(state => {
    isOnline = state.isConnected;
  });

  useEffect(() => {
    return unsubscribeNetworkEventListener();
  }, []);

  const initializeChatJS = () => {
    // To configure WebSocketManager, setGlobalConfig must be invoked
    connect.ChatSession.setGlobalConfig({
      // ...
      webSocketManagerConfig: {
        isNetworkOnline: customNetworkStatusUtil,
      }
    });
  }

  // ...
}