您好我正在使用本机的webview来显示一些HTML, 我希望每当用户点击该html中的链接时,它都会打开该用户的浏览器。
可能吗?
我最终使用了这个软件包:npmjs.com/package/react-native-communications打开浏览器。 当URL更改时,我将浏览器打开onNavigationStateChange。
现在的事情是WebView仍然继续处理请求,虽然我已经移动到浏览器,我该如何停止请求?
答案 0 :(得分:85)
这是一个完整的工作解决方案:
import React, { Component } from 'react';
import { WebView, Linking } from 'react-native';
export default class WebViewThatOpensLinksInNavigator extends Component {
render() {
const uri = 'http://stackoverflow.com/questions/35531679/react-native-open-links-in-browser';
return (
<WebView
ref={(ref) => { this.webview = ref; }}
source={{ uri }}
onNavigationStateChange={(event) => {
if (event.url !== uri) {
this.webview.stopLoading();
Linking.openURL(event.url);
}
}}
/>
);
}
}
它使用一个简单的WebView,拦截任何url更改,如果该url与原始URL不同,则停止加载,阻止页面更改,并在OS Navigator中将其打开。
答案 1 :(得分:17)
Linking.openURL(url).catch(err => console.error('An error occurred', err));
答案 2 :(得分:13)
这是我的解决方案。由于它不是通用的,您可以根据您的要求改进注入的javascript
import {
View,
WebView,
Linking,
} from 'react-native';
const injectScript = `
(function () {
window.onclick = function(e) {
e.preventDefault();
window.postMessage(e.target.href);
e.stopPropagation()
}
}());
`;
class MyWebView extends React.Component {
onMessage({ nativeEvent }) {
const data = nativeEvent.data;
if (data !== undefined && data !== null) {
Linking.openURL(data);
}
}
render() {
return (
<WebView
source={{ html: this.props.html }}
injectedJavaScript={injectScript}
onMessage={this.onMessage}
/>
)
}
}
答案 3 :(得分:5)
我找到了一种方法,但它只是一个iOS解决方案!
以下是分步说明:
'RCTLinkingIOS'
库链接到您的项目。我用过CocoaPods
这样。在您的WebView中添加&#34; onShouldStartLoadWithRequest&#34;。例如
<WebView source={{ html: content }} onShouldStartLoadWithRequest={this.onShouldStartLoadWithRequest} />
添加this.onShouldStartLoadWithRequest
功能。根据您是否要关注WebView中的链接,返回TRUE或FALSE。这基本上等同于在本机代码(Swift或Objective-C)中实现它时使用的UIWebViewDelegate实现。
onShouldStartLoadWithRequest = (event) => {
Linking.canOpenURL(event.url).then(supported => {
if (supported) {
Linking.openURL(event.url);
} else {
console.log('Don\'t know how to open URI: ' + event.url);
}
return false
});
}
确保在您的javascript源代码中导入链接:
import { AppRegistry, View, WebView, Linking } from 'react-native';
这应该可以解决问题。
有关更多信息,请参阅react-native文档: {{3}}
答案 4 :(得分:5)
使用“ stopLoading()”的一个大问题是,在Android上,它会禁用该源页面上任何其他链接的进一步点击。
WebView组件正在从核心RN中分离出来,并交到社区的手中。如果改用该版本(https://github.com/react-native-community/react-native-webview),则可以在iOS和Android上都使用“ onShouldStartLoadWithRequest”道具,这使它更加优雅。
以Damien Varron真正有用的答案为基础,下面是一个示例,说明如何利用该道具避免在跨平台工作的stopLoading:
onShouldStartLoadWithRequest={event => {
if (event.url !== uri) {
Linking.openURL(event.url)
return false
}
return true
}}
如果您的源是HTML而不是URI,则可以按照以下方法操作:
onShouldStartLoadWithRequest={event => {
if (event.url.slice(0,4) === 'http') {
Linking.openURL(event.url)
return false
}
return true
}}
正如basbase所指出的,您也可以用这种方式(我已经添加了about:blank部分)。我计划进行更多的反复试验,看看哪种方法最有效。
onShouldStartLoadWithRequest={event => {
if (!/^[data:text, about:blank]/.test(event.url)) {
Linking.openURL(event.url)
return false
}
return true
}}
答案 5 :(得分:1)
您想要阅读此内容:https://facebook.github.io/react-native/docs/linkingios.html
有可能,只需查看上面的链接&amp;你应该一切都好!
其他链接:
答案 6 :(得分:1)
可以使用内置的Linking类和react-native-webview-bridge以跨平台的方式执行此操作。
const generateLink = (text, url) => {
if (url) {
return `<a href='#' onclick='WebViewBridge.send("${url}"); return false;'>${text}</a>`;
} else {
return text;
}
};
const generateHtml = () => `<!DOCTYPE html><html><body>
${generateLink('Link text', 'http://example.com')}
</body></html>`;
使用WebViewBridge
组件呈现如下:
<WebViewBridge
javaScriptEnabled
renderLoading={() => <ActivityIndicator animating size="large" />}
source={{ html: generateHtml() }}
onBridgeMessage={url => Linking.openURL(url)}
/>
答案 7 :(得分:1)
@Damusnet 只是偶尔为我工作。我查看了它,这是我使用 react-native-webview 11.4.3 对我有用的更新代码。
import React from 'react';
import { WebView, Linking } from 'react-native';
const WebviewScreen = () => {
const uri = 'http://stackoverflow.com/questions/35531679/react-native-open-links-in-browser';
return (
<WebView
source={{ uri }}
onShouldStartLoadWithRequest={(request) => {
if (request.url !== uri) {
Linking.openURL(request.url);
return false;
}
return true;
}}
/>
)
}
答案 8 :(得分:0)
除了出色的答案https://stackoverflow.com/a/40382325/10236907:
使用source={{html: '...'}}
时,您可以使用以下方法检查外部URL的更改:
if (!/^data:text/.test(event.url)) {
答案 9 :(得分:0)
如果Android stopLoading()
中的onNavigationStateChange
不起作用,
this.webview.stopLoading();
setTimeOut( () => {
Linking.openURL(event.url)
}, 1000);
效果很好。
答案 10 :(得分:0)
使用expo的人的解决方案:
import * as WebBrowser from 'expo-web-browser';
import { WebView } from 'react-native-webview';
...
render() {
return (
<WebView
source={{
uri: uri
}}
ref={ (ref) => { this.webview = ref; } }
onNavigationStateChange={ (event) => {
if (event.url !== uri) {
this.webView.stopLoading();
WebBrowser.openBrowserAsync(event.url);
}
}}
/>
);
}
WebBrowser
通过以下方式安装:expo install expo-web-browser
答案 11 :(得分:0)
在仅在iOS上使用本地HTML文件时,此解决方案存在很多问题。 例如,当我将Instagram嵌入到Webview中时,它会自动打开。 为了解决这个问题,我添加了(仅适用于iOS):
onShouldStartLoadWithRequest={event => {
const condition = isIos ? event.navigationType == 'click' : true
if (event.url.slice(0, 4) === 'http' && condition) {
Linking.openURL(event.url)
return false
}
return true
}}
答案 12 :(得分:0)
如果您尝试打开重定向URL,但从诸如“ err_unknown_url_scheme”之类的android意图中收到错误。
检查它试图打开的内容,因为它可能检测到了android流量并试图在相应的应用程序中打开。
如果您仍然希望在Web视图中打开它,并且从重定向中获得了一个意图,请在onNavigationStateChange中将其拦截并重写:
onNavigationStateChange={event => {
if (event.url !== uri) {
if (event.url.match('intent://')) {
SetSearchClick(
event.url.replace('intent://', 'https://'),
);
}
}
}}
答案 13 :(得分:0)
<WebView
source={{uri: this.state.src}}
ref={(webView) => {
this.webView.ref = webView;
}}
onNavigationStateChange={(navState) => {
this.webView.canGoBack = navState.canGoBack;
if (!navState.url.includes('yourdomain.com')) {
Linking.openURL(navState.url);
return false;
}
}}
onShouldStartLoadWithRequest={(event) => {
if (!event.url.includes('yourdomain.com')) {
Linking.openURL(event.url);
return false;
}
return true;
}}
style={{flex: 1}}
startInLoadingState={true}
renderLoading={() => {
return (
<View style={[styles.container, styles.horizontal]}>
<ActivityIndicator size="large" color="#0000ff" />
</View>
);
}}
/>
我为此苦苦挣扎,我的用例是在单独的浏览器中打开外部链接。这个解决方案对我有用。