Integrating a ReactJS Progressive Web App (PWA) with a React Native mobile app to enable bidirectional communication
Before starting the story, let’s see why we need such kind of an old school 😊 (ionic, Sencha…..) way again in our mobile app.
When it comes to large scale apps where a number of teams develop separate features for a single app, and if we have a never ending huge backlog. So in such a scenario most of the time BU (Business users) may like to deliver new features to CX (Customers) without an app release. A seamless app update for react-native app could be achieved through using the microsoft/react-native-code-push as well but 🤓. Will discuss the integration and usage of microsoft/react-native-code-push on another day.
In here I uses a ReactJS app as the web app and an Express.js server as the server application these things could change to whatever based on your requirement. Also for the mobile app React Native has used in here, but it is possible to do this same thing with native android or iOS app as well (flutter also). Here the main thing you need to understand is only the functionality of the process.
Sample code : el173/rn-webview-coupled-pwa
In this article, it illustrates the subject of my focus and what I aim to achieve.
1. Create RN app and add react native web view
Refer official documentation to create react native CLI app and add the react-native-webview.
2. Create ReactJS PWA
A good guide to create PWA using : PWA React tutorial: How to Build PWA with React in 5 Steps
3. Create communication functionality between mobile and PWA
Here it uses the post messages to do the communication between two front ends. So it’s good have some understanding regarding the web postMessage() method.
Read more : https://developer.mozilla.org/enUS/docs/Web/API/Window/postMessage
- PWA to Mobile
— First a listener should attach to the mobile web view in order to listen whatever messages posted from the web view.
// Listener function
const handleMessage = message => {
Alert.alert(message.nativeEvent.data);
};
// Webview component
<WebView
source={{uri: STATIC_WEB_URL}}
startInLoadingState={true}
renderLoading={() => <ActivityIndicator />}
onMessage={handleMessage}
onError={syntheticEvent => {
const {nativeEvent} = syntheticEvent;
console.warn('WebView error: ', nativeEvent);
}}
/>
— Okay now from the PWA, it needed to send messages to the mobile app
For that window.ReactNativeWebView.postMessage
could be used as per the react-native-webview API guide.
const sendMessage = () => {
window.ReactNativeWebView.postMessage('Hi from PWA');
};
/**
* window.ReactNativeWebView.postMessage accepts one argument, data
* which will be available on the event object, event.nativeEvent.data. data must be a string
*/
// Button action to send message
const handleMessage = message => {
Alert.alert(message.nativeEvent.data);
};
// Button component
<button onClick={sendMessage}>
Say Hi
</button>
From web to mobile communication is now completed 🙌✊🥳🎉👏.
- Now let’s see the vice versa communication, Mobile to PWA
— In PWA also it needed to implement a message listener first.
useEffect(() => {
const messageListener = window.addEventListener('message', (e) => {
alert(JSON.stringify(e.data));
});
return messageListener;
}, []);
— Now It should able to send messages from the mobile app in order to invoke the above message listener.
For this there are two ways based on the requirement,
- Send message onLoad of web view
- Send messages based on user interactions (Ex. button click)
You can try out first option using injectedJavaScript
API
To pass messages based on user interactions or manually (means not onLoad webview) it needed to have a saved reference of webview. Below example it shows the way it could save webview ref object.
// Variable to hold webview ref
const webViewRef = useRef(null);
<WebView
source={{uri: STATIC_WEB_URL}}
startInLoadingState={true}
renderLoading={() => <ActivityIndicator />}
onMessage={handleMessage}
ref={webViewRef} // Assign webview ref to the `webViewRef` variable while initial rendering
onError={syntheticEvent => {
const {nativeEvent} = syntheticEvent;
console.warn('WebView error: ', nativeEvent);
}}
/>
Okay now we have a webview reference which we could use any time we want
It’s all set now to send messages to the PWA except a message sender. Now we’ll see how it could write a function to send messages using the previously saved webview reference object.
// Send message function
const sendMessage = () => {
if (webViewRef.current) {
webViewRef.current.postMessage('Hi from Mobile');
}
};
// Button component to send message
<Button title={'Hello'} onPress={sendMessage} />
Mobile to PWA communication also completed 🙌✊.
4. Simple implementation with added security (web view authentication)
To be continued …….. (will update the link later 😊😊)
This is just a basic example of usage of react-native-web view to interact with PWA. Using this kind of a native wrapper (or native/fultter) to any of PWA it is possible to break all the limitation today we are facing with PWA mobile version. If the PWA mobile app ships with fully native friendly PWA wrapper then, we can use the all PWA advantages with fully native accessibilities.