A reusable React Native WebView component designed for flexible interaction between web content and your React Native application. It simplifies common tasks like navigating React Native screens from the web, triggering native share functionality, and injecting JavaScript for two-way communication.
The CustomWebView
component provides a standardized JavaScript bridge (window.ReactNativeWebViewBridge
) that is automatically injected into your web content. This bridge allows your web application's JavaScript to easily send structured messages to the React Native application, and vice-versa.
- Standardized JS Bridge: Injects
window.ReactNativeWebViewBridge
into the web content for easy communication. - Web to React Native Communication:
window.ReactNativeWebViewBridge.navigate(details)
: Request React Native to navigate to a different screen.window.ReactNativeWebViewBridge.share(details)
: Request React Native to trigger the native sharing dialog.window.ReactNativeWebViewBridge.sendEvent(eventType, eventData)
: Send custom events with arbitrary data.window.ReactNativeWebViewBridge.postMessage({ type: "...", payload: ... })
: The underlying method for all bridge communication.
- React Native to Web Communication:
- Use the component's
ref
to callinjectJavaScript("yourJSCode(); true;")
to execute JavaScript within the WebView.
- Use the component's
- Customizable:
- Pass
uri
to load any web page. - Handle messages from the web via the
onMessage
prop. - Inject custom JavaScript before or after the main bridge setup.
- Set custom HTTP headers (e.g., for authentication).
- Control loading indicators.
- Pass
- Exposes WebView Controls: Provides access to common WebView methods like
reload()
,goBack()
, etc., via itsref
.
-
Import the component:
import CustomWebView, { WebViewRef } from './path/to/your/CustomWebView'; import { useRef } from 'react'; import { useNavigation } from '@react-navigation/native'; // Or your navigation library import { Share, Alert } from 'react-native';
-
Use it in your component:
const MyScreenWithWebView = () => { const webViewRef = useRef<WebViewRef>(null); const navigation = useNavigation(); const handleWebViewMessage = (message) => { console.log('RN: Received message:', message.type, message.payload); switch (message.type) { case 'NAVIGATE': if (message.payload?.routeName) { navigation.navigate(message.payload.routeName, message.payload.params); } break; case 'SHARE': if (message.payload) { Share.share({ message: message.payload.message || '', url: message.payload.url, title: message.payload.title, }); } break; case 'CUSTOM_EVENT_FROM_WEB': Alert.alert('Custom Event', `Received: ${JSON.stringify(message.payload)}`); break; // ... handle other message types } }; const sendDataToWebView = () => { if (webViewRef.current) { const script = ` if (window.receiveDataFromRN) { window.receiveDataFromRN({ content: 'Hello from React Native!' }); } true; // Important! `; webViewRef.current.injectJavaScript(script); } }; return ( <CustomWebView ref={webViewRef} uri="https://your-web-app.com/page.html" onMessage={handleWebViewMessage} // Optional props authToken="your_auth_token_if_needed" showsLoadingIndicator={true} onShouldStartLoadWithRequest={(request) => { // Control navigation: return true to allow, false to block // or open in system browser: Linking.openURL(request.url); return false; console.log('Attempting to load:', request.url); return true; }} /> // <Button title="Send to Web" onPress={sendDataToWebView} /> ); };
Your web application's JavaScript can interact with the React Native app using the window.ReactNativeWebViewBridge
object.
<!DOCTYPE html>
<html>
<head>
<title>Web Page</title>
<script>
function requestNavigation() {
if (window.ReactNativeWebViewBridge && window.ReactNativeWebViewBridge.navigate) {
window.ReactNativeWebViewBridge.navigate({ routeName: 'UserProfile', params: { id: '123' } });
} else {
console.warn('ReactNativeWebViewBridge.navigate not available.');
}
}
function requestShare() {
if (window.ReactNativeWebViewBridge && window.ReactNativeWebViewBridge.share) {
window.ReactNativeWebViewBridge.share({
url: window.location.href,
message: 'Check out this page!',
title: document.title
});
} else {
console.warn('ReactNativeWebViewBridge.share not available.');
}
}
function sendCustomEvent() {
if (window.ReactNativeWebViewBridge && window.ReactNativeWebViewBridge.sendEvent) {
window.ReactNativeWebViewBridge.sendEvent('MY_CUSTOM_ACTION', { data: 'some value', timestamp: Date.now() });
} else {
console.warn('ReactNativeWebViewBridge.sendEvent not available.');
}
}
// Function to be called by React Native's injectJavaScript
window.receiveDataFromRN = function(data) {
console.log('Web: Received data from RN:', data);
alert('Message from RN: ' + data.content);
};
</script>
</head>
<body>
<button onclick="requestNavigation()">Go to Profile (RN)</button>
<button onclick="requestShare()">Share this Page (Native)</button>
<button onclick="sendCustomEvent()">Send Custom Event to RN</button>
</body>
</html>
Prop | Type | Default | Description |
---|---|---|---|
uri |
string |
Required | The URL of the web page to load. |
onMessage |
(message: { type: string; payload?: any }) => void |
Required | Callback function to handle messages sent from the WebView's JavaScript via the bridge. |
authToken |
string |
undefined |
Optional authentication token to be included in the Authorization header. |
acceptLanguage |
string |
undefined |
Optional Accept-Language header value. |
additionalHeaders |
Record<string, string> |
{} |
Any other custom HTTP headers to send with the initial request. |
injectedJavaScriptBeforeBridge |
string |
undefined |
Custom JavaScript string to inject before the window.ReactNativeWebViewBridge is set up. |
injectedJavaScriptAfterBridge |
string |
undefined |
Custom JavaScript string to inject after the window.ReactNativeWebViewBridge is set up. |
baseInjectedJavaScript |
string |
Internal bridge script | Allows overriding the entire default bridge script if needed for advanced customization. |
showsLoadingIndicator |
boolean |
true |
Whether to show a default loading indicator while the page loads. |
customLoadingComponent |
React.ReactNode |
undefined |
A custom React component to display as a loading indicator. |
style |
ViewStyle |
{ flex: 1 } |
Style for the WebView container. |
onShouldStartLoadWithRequest |
(event: WebViewNavigationEvent) => boolean |
undefined (passes to react-native-webview ) |
Function that allows you to intercept web requests and decide whether to load them in the WebView or handle them differently (e.g., open externally). |
... | WebViewProps |
Other standard react-native-webview props are passed through. |
You can get a ref
to the CustomWebView
component to access these methods:
injectJavaScript(script: string)
: Executes JavaScript code within the loaded web page.reload()
: Reloads the current web page.goBack()
: Navigates back in the WebView's history.goForward()
: Navigates forward in the WebView's history.stopLoading()
: Stops the WebView from loading the current page.
一个可复用的 React Native WebView 组件,专为实现 Web 内容与 React Native 应用之间的灵活交互而设计。它简化了常见任务,例如从 Web 页面导航到 React Native 屏幕、触发原生分享功能以及注入 JavaScript 以进行双向通信。
###核心理念
CustomWebView
组件提供了一个标准化的 JavaScript 桥接 (window.ReactNativeWebViewBridge
),它会自动注入到您的 Web 内容中。这个桥接允许您的 Web 应用的 JavaScript 轻松地向 React Native 应用发送结构化消息,反之亦然。
###主要特性
- 标准化 JS 桥接: 向 Web 内容注入
window.ReactNativeWebViewBridge
以方便通信。 - Web 到 React Native 通信:
window.ReactNativeWebViewBridge.navigate(details)
: 请求 React Native 导航到不同的屏幕。window.ReactNativeWebViewBridge.share(details)
: 请求 React Native 触发原生分享对话框。window.ReactNativeWebViewBridge.sendEvent(eventType, eventData)
: 发送带有任意数据的自定义事件。window.ReactNativeWebViewBridge.postMessage({ type: "...", payload: ... })
: 所有桥接通信的底层方法。
- React Native 到 Web 通信:
- 使用组件的
ref
调用injectJavaScript("yourJSCode(); true;")
在 WebView 内执行 JavaScript。
- 使用组件的
- 可定制:
- 传递
uri
加载任何网页。 - 通过
onMessage
prop 处理来自 Web 的消息。 - 在主桥接设置之前或之后注入自定义 JavaScript。
- 设置自定义 HTTP 头部 (例如,用于身份验证)。
- 控制加载指示器。
- 传递
- 暴露 WebView 控件: 通过其
ref
提供对常见 WebView 方法的访问,如reload()
、goBack()
等。
###如何使用 (React Native 端)
-
导入组件:
import CustomWebView, { WebViewRef } from './path/to/your/CustomWebView'; // 调整路径 import { useRef } from 'react'; import { useNavigation } from '@react-navigation/native'; // 或您的导航库 import { Share, Alert } from 'react-native';
-
在您的组件中使用它:
const MyScreenWithWebView = () => { const webViewRef = useRef<WebViewRef>(null); const navigation = useNavigation(); const handleWebViewMessage = (message) => { console.log('RN: 收到消息:', message.type, message.payload); switch (message.type) { case 'NAVIGATE': if (message.payload?.routeName) { navigation.navigate(message.payload.routeName, message.payload.params); } break; case 'SHARE': if (message.payload) { Share.share({ message: message.payload.message || '', url: message.payload.url, title: message.payload.title, }); } break; case 'CUSTOM_EVENT_FROM_WEB': Alert.alert('自定义事件', `收到: ${JSON.stringify(message.payload)}`); break; // ... 处理其他消息类型 } }; const sendDataToWebView = () => { if (webViewRef.current) { const script = ` if (window.receiveDataFromRN) { window.receiveDataFromRN({ content: '来自 React Native 的问候!' }); } true; // 重要! `; webViewRef.current.injectJavaScript(script); } }; return ( <CustomWebView ref={webViewRef} uri="https://your-web-app.com/page.html" // 替换为您的 Web 应用 URL onMessage={handleWebViewMessage} // 可选 props authToken="your_auth_token_if_needed" // 如果需要,传入认证 token showsLoadingIndicator={true} onShouldStartLoadWithRequest={(request) => { // 控制导航: 返回 true 允许加载, false 阻止 // 或在系统浏览器中打开: Linking.openURL(request.url); return false; console.log('尝试加载:', request.url); return true; }} /> // <Button title="发送到 Web" onPress={sendDataToWebView} /> ); };
###如何使用 (Web 页面端 - 供 Web 开发人员使用)
您的 Web 应用的 JavaScript 可以使用 window.ReactNativeWebViewBridge
对象与 React Native 应用进行交互。
<!DOCTYPE html>
<html>
<head>
<title>Web 页面</title>
<script>
function requestNavigation() {
if (window.ReactNativeWebViewBridge && window.ReactNativeWebViewBridge.navigate) {
window.ReactNativeWebViewBridge.navigate({ routeName: 'UserProfile', params: { id: '123' } });
} else {
console.warn('ReactNativeWebViewBridge.navigate 不可用。');
}
}
function requestShare() {
if (window.ReactNativeWebViewBridge && window.ReactNativeWebViewBridge.share) {
window.ReactNativeWebViewBridge.share({
url: window.location.href,
message: '快来看看这个页面!',
title: document.title
});
} else {
console.warn('ReactNativeWebViewBridge.share 不可用。');
}
}
function sendCustomEvent() {
if (window.ReactNativeWebViewBridge && window.ReactNativeWebViewBridge.sendEvent) {
window.ReactNativeWebViewBridge.sendEvent('MY_CUSTOM_ACTION', { data: '一些数据', timestamp: Date.now() });
} else {
console.warn('ReactNativeWebViewBridge.sendEvent 不可用。');
}
}
// 由 React Native 的 injectJavaScript 调用的函数
window.receiveDataFromRN = function(data) {
console.log('Web: 收到来自 RN 的数据:', data);
alert('来自 RN 的消息: ' + data.content);
};
</script>
</head>
<body>
<button onclick="requestNavigation()">前往个人资料 (RN)</button>
<button onclick="requestShare()">分享此页面 (原生)</button>
<button onclick="sendCustomEvent()">向 RN 发送自定义事件</button>
</body>
</html>
###主要 Props
Prop | 类型 | 默认值 | 描述 |
---|---|---|---|
uri |
string |
必需 | 要加载的网页 URL。 |
onMessage |
(message: { type: string; payload?: any }) => void |
必需 | 回调函数,用于处理通过桥接从 WebView 的 JavaScript 发送的消息。 |
authToken |
string |
undefined |
可选的认证令牌,将包含在 Authorization 头部中。 |
acceptLanguage |
string |
undefined |
可选的 Accept-Language 头部值。 |
additionalHeaders |
Record<string, string> |
{} |
随初始请求一起发送的任何其他自定义 HTTP 头部。 |
injectedJavaScriptBeforeBridge |
string |
undefined |
在 window.ReactNativeWebViewBridge 设置之前注入的自定义 JavaScript 字符串。 |
injectedJavaScriptAfterBridge |
string |
undefined |
在 window.ReactNativeWebViewBridge 设置之后注入的自定义 JavaScript 字符串。 |
baseInjectedJavaScript |
string |
内部桥接脚本 | 如果需要高级定制,允许覆盖整个默认桥接脚本。 |
showsLoadingIndicator |
boolean |
true |
页面加载时是否显示默认加载指示器。 |
customLoadingComponent |
React.ReactNode |
undefined |
作为加载指示器显示的自定义 React 组件。 |
style |
ViewStyle |
{ flex: 1 } |
WebView 容器的样式。 |
onShouldStartLoadWithRequest |
(event: WebViewNavigationEvent) => boolean |
undefined (传递给 react-native-webview ) |
函数,允许您拦截 Web 请求并决定是在 WebView 中加载它们还是以不同方式处理它们(例如,在外部打开)。 |
... | WebViewProps |
其他标准的 react-native-webview props 会被传递。 |
###暴露的 Ref 方法 (WebViewRef
)
您可以获取 CustomWebView
组件的 ref
以访问这些方法:
injectJavaScript(script: string)
: 在加载的网页中执行 JavaScript 代码。reload()
: 重新加载当前网页。goBack()
: 在 WebView 的历史记录中后退。goForward()
: 在 WebView 的历史记录中前进。stopLoading()
: 停止 WebView 加载当前页面。
一個可複用的 React Native WebView 組件,專為實現 Web 內容與 React Native 應用程式之間的靈活互動而設計。它簡化了常見任務,例如從 Web 頁面導航到 React Native 螢幕、觸發原生分享功能以及注入 JavaScript 以進行雙向通訊。
###核心理念
CustomWebView
組件提供了一個標準化的 JavaScript 橋接 (window.ReactNativeWebViewBridge
),它會自動注入到您的 Web 內容中。這個橋接允許您的 Web 應用程式的 JavaScript 輕鬆地向 React Native 應用程式發送結構化訊息,反之亦然。
###主要特性
- 標準化 JS 橋接: 向 Web 內容注入
window.ReactNativeWebViewBridge
以方便通訊。 - Web 到 React Native 通訊:
window.ReactNativeWebViewBridge.navigate(details)
: 請求 React Native 導航到不同的螢幕。window.ReactNativeWebViewBridge.share(details)
: 请求 React Native 觸發原生分享對話框。window.ReactNativeWebViewBridge.sendEvent(eventType, eventData)
: 發送帶有任意資料的自訂事件。window.ReactNativeWebViewBridge.postMessage({ type: "...", payload: ... })
: 所有橋接通訊的底層方法。
- React Native 到 Web 通訊:
- 使用組件的
ref
呼叫injectJavaScript("yourJSCode(); true;")
在 WebView 內執行 JavaScript。
- 使用組件的
- 可自訂:
- 傳遞
uri
載入任何網頁。 - 透過
onMessage
prop 處理來自 Web 的訊息。 - 在主橋接設定之前或之後注入自訂 JavaScript。
- 設定自訂 HTTP 標頭 (例如,用於身份驗證)。
- 控制載入指示器。
- 傳遞
- 暴露 WebView 控制項: 透過其
ref
提供對常見 WebView 方法的存取,如reload()
、goBack()
等。
###如何使用 (React Native 端)
-
匯入組件:
import CustomWebView, { WebViewRef } from './path/to/your/CustomWebView'; // 調整路徑 import { useRef } from 'react'; import { useNavigation } from '@react-navigation/native'; // 或您的導航庫 import { Share, Alert } from 'react-native';
-
在您的組件中使用它:
const MyScreenWithWebView = () => { const webViewRef = useRef<WebViewRef>(null); const navigation = useNavigation(); const handleWebViewMessage = (message) => { console.log('RN: 收到訊息:', message.type, message.payload); switch (message.type) { case 'NAVIGATE': if (message.payload?.routeName) { navigation.navigate(message.payload.routeName, message.payload.params); } break; case 'SHARE': if (message.payload) { Share.share({ message: message.payload.message || '', url: message.payload.url, title: message.payload.title, }); } break; case 'CUSTOM_EVENT_FROM_WEB': Alert.alert('自訂事件', `收到: ${JSON.stringify(message.payload)}`); break; // ... 處理其他訊息類型 } }; const sendDataToWebView = () => { if (webViewRef.current) { const script = ` if (window.receiveDataFromRN) { window.receiveDataFromRN({ content: '來自 React Native 的問候!' }); } true; // 重要! `; webViewRef.current.injectJavaScript(script); } }; return ( <CustomWebView ref={webViewRef} uri="https://your-web-app.com/page.html" // 替換為您的 Web 應用程式 URL onMessage={handleWebViewMessage} // 可選 props authToken="your_auth_token_if_needed" // 如果需要,傳入認證 token showsLoadingIndicator={true} onShouldStartLoadWithRequest={(request) => { // 控制導航: 返回 true 允許載入, false 阻止 // 或在系統瀏覽器中開啟: Linking.openURL(request.url); return false; console.log('嘗試載入:', request.url); return true; }} /> // <Button title="傳送到 Web" onPress={sendDataToWebView} /> ); };
###如何使用 (Web 頁面端 - 供 Web 開發人員使用)
您的 Web 應用程式的 JavaScript 可以使用 window.ReactNativeWebViewBridge
物件與 React Native 應用程式進行互動。
<!DOCTYPE html>
<html>
<head>
<title>Web 頁面</title>
<script>
function requestNavigation() {
if (window.ReactNativeWebViewBridge && window.ReactNativeWebViewBridge.navigate) {
window.ReactNativeWebViewBridge.navigate({ routeName: 'UserProfile', params: { id: '123' } });
} else {
console.warn('ReactNativeWebViewBridge.navigate 不可用。');
}
}
function requestShare() {
if (window.ReactNativeWebViewBridge && window.ReactNativeWebViewBridge.share) {
window.ReactNativeWebViewBridge.share({
url: window.location.href,
message: '快來看看這個頁面!',
title: document.title
});
} else {
console.warn('ReactNativeWebViewBridge.share 不可用。');
}
}
function sendCustomEvent() {
if (window.ReactNativeWebViewBridge && window.ReactNativeWebViewBridge.sendEvent) {
window.ReactNativeWebViewBridge.sendEvent('MY_CUSTOM_ACTION', { data: '一些資料', timestamp: Date.now() });
} else {
console.warn('ReactNativeWebViewBridge.sendEvent 不可用。');
}
}
// 由 React Native 的 injectJavaScript 呼叫的函數
window.receiveDataFromRN = function(data) {
console.log('Web: 收到來自 RN 的資料:', data);
alert('來自 RN 的訊息: ' + data.content);
};
</script>
</head>
<body>
<button onclick="requestNavigation()">前往個人資料 (RN)</button>
<button onclick="requestShare()">分享此頁面 (原生)</button>
<button onclick="sendCustomEvent()">向 RN 發送自訂事件</button>
</body>
</html>
###主要 Props
Prop | 類型 | 預設值 | 描述 |
---|---|---|---|
uri |
string |
必需 | 要載入的網頁 URL。 |
onMessage |
(message: { type: string; payload?: any }) => void |
必需 | 回呼函數,用於處理透過橋接從 WebView 的 JavaScript 發送的訊息。 |
authToken |
string |
undefined |
可選的認證權杖,將包含在 Authorization 標頭中。 |
acceptLanguage |
string |
undefined |
可選的 Accept-Language 標頭值。 |
additionalHeaders |
Record<string, string> |
{} |
隨初始請求一起發送的任何其他自訂 HTTP 標頭。 |
injectedJavaScriptBeforeBridge |
string |
undefined |
在 window.ReactNativeWebViewBridge 設定之前注入的自訂 JavaScript 字串。 |
injectedJavaScriptAfterBridge |
string |
undefined |
在 window.ReactNativeWebViewBridge 設定之後注入的自訂 JavaScript 字串。 |
baseInjectedJavaScript |
string |
內部橋接腳本 | 如果需要進階自訂,允許覆寫整個預設橋接腳本。 |
showsLoadingIndicator |
boolean |
true |
頁面載入時是否顯示預設載入指示器。 |
customLoadingComponent |
React.ReactNode |
undefined |
作為載入指示器顯示的自訂 React 組件。 |
style |
ViewStyle |
{ flex: 1 } |
WebView 容器的樣式。 |
onShouldStartLoadWithRequest |
(event: WebViewNavigationEvent) => boolean |
undefined (傳遞給 react-native-webview ) |
函數,允許您攔截 Web 請求並決定是在 WebView 中載入它們還是以不同方式處理它們(例如,在外部開啟)。 |
... | WebViewProps |
其他標準的 react-native-webview props 會被傳遞。 |
###暴露的 Ref 方法 (WebViewRef
)
您可以獲取 CustomWebView
組件的 ref
以存取這些方法:
injectJavaScript(script: string)
: 在載入的網頁中執行 JavaScript 程式碼。reload()
: 重新載入目前網頁。goBack()
: 在 WebView 的歷史記錄中後退。goForward()
: 在 WebView 的歷史記錄中前進。stopLoading()
: 停止 WebView 載入目前頁面。