iTranslated by AI
Displaying Web Content in React Native Using WebView
Introduction
Developing a smartphone app can involve many different backgrounds.
In the case of personal development, you might want to "create something easy to develop like a TODO list while also learning the technology," whereas in a larger-scale scenario, you might want to "release a mobile version of an existing web service."
Especially in the latter case, the approach is often less about building a mobile app from scratch and more about adapting "what's currently on the web" into a form optimized for smartphones (plus adding mobile-specific features like push notifications).
If the web side is responsive, there might be functions or screens where you think, "Wait, can't I just use this as is?"
Obvious examples would be FAQ screens or Terms of Service screens, which should look fine with the same appearance on both a mobile app and a browser.
In this article, I will introduce how to leverage existing Web resources as they are by using react-native-webview in an app developed with ReactNative.
What is WebView anyway?
Many people may have heard the term WebView, even outside the context of ReactNative.
A WebView is a feature that allows you to display Web content like a browser within a smartphone app.
Depending on the app, some display almost all screens using WebView, while others use Web resources only for specific points, so the use cases vary widely.
Prerequisites
react@16.13.1-
react-native@0.63.3
We will be usingTypeScript.
Installation
- Reference: GitHub | react-native-webview
yarn add react-native-webview
Furthermore, for ios, a pod install is required.
cd ios && pod install
Basics: "Displaying Content"
First, I will introduce the basic method of displaying content.
You will be displaying HTML, and there are two ways to do it.
1. Passing HTML as a String
The most standard way is to pass the HTML content directly as a string.
In the example below, a simple HTML content defined as a string type is displayed.
import React from 'react';
import { SafeAreaView, StyleSheet, StatusBar} from 'react-native';
import { WebView } from 'react-native-webview';
// HTML to be displayed in WebView
const html : string = `
<html>
<head></head>
<body>
<h1 style="font-size:56;color:red;" >Title</h1>
<p style="font-size:44px;color:blue;font-weight:bold;" >This page is html.</p>
</body>
</html>
`;
const App: React.FC = () => {
return (
<>
<StatusBar barStyle="dark-content" />
<SafeAreaView style={{flex: 1}}>
<WebView source={{html: html}} />
</SafeAreaView>
</>
);
};
const styles = StyleSheet.create({});
export default App;
Output
You can see that even the style specifications are applied correctly.
2. Specifying a URI
In the examples mentioned at the beginning, you will likely use this pattern more often.
To display existing Web content, you specify it as a uri.
In the following example, the Zenn top page is specified.
import React from 'react';
import { SafeAreaView, StyleSheet, StatusBar} from 'react-native';
import { WebView } from 'react-native-webview';
const App: React.FC = () => {
return (
<>
<StatusBar barStyle="dark-content" />
<SafeAreaView style={{flex: 1}}>
<WebView source={{uri: "https://zenn.dev"}} />
</SafeAreaView>
</>
);
};
const styles = StyleSheet.create({});
export default App;
Output
Because Zenn has a responsive design, it is displayed without breaking even when shown in a WebView.
The UI is good enough to be used as a smartphone app as it is.
Advanced: "Sending and Receiving Data"
By now, we've learned how to perform basic content display.
However, this only displays the content; it doesn't allow for sending or receiving data on the smartphone app side.
For example, you might want to "trigger a function defined in ReactNative when a button is pressed in the WebView" or "have the ReactNative side receive the results of a process performed in the WebView."
1. "Passing JS to the Web Side with injectedJavaScript"
By specifying the injectedJavaScript parameter of the WebView, you can pass JS defined on the ReactNative side to the Web content side.
If you want to define and pass a function for when a button is pressed, you need to specify injectedJavaScriptBeforeContentLoaded because the JS needs to be loaded before the content.
import React from 'react';
import { SafeAreaView, StyleSheet, StatusBar} from 'react-native';
import { WebView } from 'react-native-webview';
// Code to pass to the WebView
const injectedCode : string = `
function fireInjectedJavaScript(){
alert('Executed code passed from ReactNative!');
}
`;
// HTML to be displayed in the WebView
const html : string = `
<html>
<head></head>
<body>
<form name="test">
<input type="button" value="injectedJavaScript" onClick="fireInjectedJavaScript()">
</form>
</body>
</html>
`;
const App: React.FC = () => {
return (
<>
<StatusBar barStyle="dark-content" />
<SafeAreaView style={{flex: 1}}>
<WebView
source={{html: html}}
injectedJavaScriptBeforeContentLoaded={injectedCode} />
</SafeAreaView>
</>
);
};
const styles = StyleSheet.create({});
export default App;
Output
By tapping the displayed button, you can confirm that the function passed from the ReactNative side is executed.
2. "Passing Values from JS to ReactNative with onMessage"
If you want to return some value from the Web content side to ReactNative, you can specify an event handler in onMessage.
The value that can be obtained in the event is a type called WebViewMessageEvent, which contains various triggered event information. The actual passed value is stored within nativeEvent.data.
On the Web content side, you then execute window.ReactNativeWebView.postMessage() and specify the value you want to pass as an argument.
import React from 'react';
import { SafeAreaView, StyleSheet, StatusBar} from 'react-native';
import { WebView, WebViewMessageEvent } from 'react-native-webview';
// Code to pass to the WebView
const injectedCode : string = `
function fireInjectedJavaScript(){
window.ReactNativeWebView.postMessage('Executed code passed from ReactNative!');
}
`;
// HTML to be displayed in the WebView
const html : string = `
<html>
<head></head>
<body>
<form name="test">
<input type="button" value="injectedJavaScript" onClick="fireInjectedJavaScript()">
</form>
</body>
</html>
`;
// Data acquisition event from the WebView side
const onMessageFromHtml = (event : WebViewMessageEvent) => {
// The value is inside event.nativeEvent.data
console.log(event.nativeEvent.data);
}
const App: React.FC = () => {
return (
<>
<StatusBar barStyle="dark-content" />
<SafeAreaView style={{flex: 1}}>
<WebView
source={{html: html}}
injectedJavaScriptBeforeContentLoaded={injectedCode}
onMessage={onMessageFromHtml} />
</SafeAreaView>
</>
);
};
const styles = StyleSheet.create({});
export default App;
Output
By pressing the button displayed on the screen, the value was sent from the Web content side to ReactNative and displayed in the log.
LOG Executed code passed from ReactNative!
Summary
In this article, I introduced react-native-webview, a library for displaying Web content on ReactNative apps.
Depending on the content of the app you want to create, you might be able to handle most of it with Web content.
I highly recommend reusing parts wherever possible, as this can be effective in reducing development costs.
Additionally, if you create campaign screens that appear at the beginning of the app using WebView, you won't need to update the app and publish it to the store every time the campaign changes, making it useful in those situations as well.
Discussion