diff --git a/widgets/easyWebsocketNative/src/EZWebsocketNative.tsx b/widgets/easyWebsocketNative/src/EZWebsocketNative.tsx index 63a5c87..1de6257 100644 --- a/widgets/easyWebsocketNative/src/EZWebsocketNative.tsx +++ b/widgets/easyWebsocketNative/src/EZWebsocketNative.tsx @@ -1,5 +1,5 @@ import { MutableRefObject, useEffect, useRef } from "react"; -import { TextStyle, ViewStyle } from "react-native"; +import { TextStyle, ViewStyle, AppState, AppStateStatus } from "react-native"; import { Style } from "@mendix/pluggable-widgets-tools"; @@ -30,14 +30,7 @@ export function EZWebsocketNative({ // Check if there is no open connection already if ( connection.current === null && - // Make sure all values are initiated - objectId.status === "available" && - websocketIdentifier.status === "available" && - (!messageAttribute || messageAttribute.status === "available") && - (!onCloseMicroflowParameterValue || onCloseMicroflowParameterValue.status === "available") && - (!actionConfig || !actionConfig.find(config => { - return config.action?.canExecute == false; //This check ensures parameters from Datasource flows are available in actions - })) + canStartConnection() ) { startConnection(); } @@ -45,11 +38,27 @@ export function EZWebsocketNative({ useEffect(() => { return () => { - // Close connection on unmount + // Close connection on unmount and empty connection ref so we can reconnect on remount connection.current?.close(); + connection.current = null; }; }, []); + useEffect(() => { + //Add EventListener for AppState changes to be able to reconnect when the app comes back from background and connection was silently closed + const sub = AppState.addEventListener("change", (nextState: AppStateStatus) => { + if (nextState === "active") { + if (canStartConnection()) { + reconnect(); + } else { + console.debug("Skipped reconnect on resume: parameters not ready yet"); + } + } + }); + + return () => sub.remove(); + }, []); + const startConnection = () => { // Open websocket connection // The replace action makes sure that applications without ssl connect to ws:// and with ssl connect to wss:// @@ -79,6 +88,10 @@ export function EZWebsocketNative({ ws.onclose = event => { console.debug(event); + + // Mark as closed so we can reconnect + connection.current = null; + // Timeout event if (event.code === 1001 && timeoutAction && timeoutAction.canExecute) { timeoutAction.execute(); @@ -128,5 +141,32 @@ export function EZWebsocketNative({ }; }; + const reconnect = () => { + // If there is an existing socket, close it first + if (connection.current && connection.current.readyState !== WebSocket.CLOSED) { + try { + connection.current.close(); + } catch (e) { + console.warn("Error while closing WS before reconnect", e); + } + } + connection.current = null; + startConnection(); + }; + + const canStartConnection = (): boolean => { + return ( + // Make sure all values are initiated. Made into reusable function as it is used in multiple places now + objectId.status === "available" && + websocketIdentifier.status === "available" && + (!messageAttribute || messageAttribute.status === "available") && + (!onCloseMicroflowParameterValue || onCloseMicroflowParameterValue.status === "available") && + (!actionConfig || + !actionConfig.find(config => { + return config.action?.canExecute == false; + })) + ); +}; + return null; } diff --git a/widgets/tests/testProject/widgets/jjrplus.EZWebsocketNative.mpk b/widgets/tests/testProject/widgets/jjrplus.EZWebsocketNative.mpk index 479e7d0..fbcd1c8 100644 Binary files a/widgets/tests/testProject/widgets/jjrplus.EZWebsocketNative.mpk and b/widgets/tests/testProject/widgets/jjrplus.EZWebsocketNative.mpk differ