React Native - 在浏览器中打开链接

时间:2016-02-21 02:42:07

标签: react-native

您好我正在使用本机的webview来显示一些HTML, 我希望每当用户点击该html中的链接时,它都会打开该用户的浏览器。

可能吗?

编辑1:

我最终使用了这个软件包:npmjs.com/package/react-native-communications打开浏览器。 当URL更改时,我将浏览器打开onNavigationStateChange。

现在的事情是WebView仍然继续处理请求,虽然我已经移动到浏览器,我该如何停止请求?

14 个答案:

答案 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中将其打开。

ios simulator

答案 1 :(得分:17)

Linking.openURL(url).catch(err => console.error('An error occurred', err));

https://facebook.github.io/react-native/docs/linking.html

答案 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解决方案!

以下是分步说明:

  1. 'RCTLinkingIOS'库链接到您的项目。我用过CocoaPods 这样。
  2. 在您的WebView中添加&#34; onShouldStartLoadWithRequest&#34;。例如

    <WebView source={{ html: content }} onShouldStartLoadWithRequest={this.onShouldStartLoadWithRequest} />

  3. 添加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
         });
    }
    
  4. 确保在您的javascript源代码中导入链接:

    import { AppRegistry, View, WebView, Linking } from 'react-native';

  5. 这应该可以解决问题。

    有关更多信息,请参阅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;你应该一切都好!

其他链接:

https://github.com/ivanph/react-native-webintent

https://www.npmjs.com/package/react-native-browser

答案 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)

  1. 如果您尝试打开重定向URL,但从诸如“ err_unknown_url_scheme”之类的android意图中收到错误。

  2. 检查它试图打开的内容,因为它可能检测到了android流量并试图在相应的应用程序中打开。

  3. 如果您仍然希望在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>
        );
      }}
    />

我为此苦苦挣扎,我的用例是在单独的浏览器中打开外部链接。这个解决方案对我有用。