Zanam
Zanam

Reputation: 4807

Open react native expo app external links outside the app

I am using the following code. Apple is not pleased that all external links are opening within app. How should I modify my code below so that external links open in outisde app safari instead of within app safari.

My App.js is as following:

import { StatusBar } from 'expo-status-bar';
import React, { useState, useRef } from 'react'
import {ActivityIndicator, Platform,  TouchableOpacity, Text, SafeAreaView, StyleSheet, View} from "react-native";
import { WebView } from 'react-native-webview';
import { NavigationContainer } from '@react-navigation/native';
import { Ionicons } from '@expo/vector-icons'
import Constants from 'expo-constants'
const App = () => {
  const [canGoBack, setCanGoBack] = useState(false)
  const [canGoForward, setCanGoForward] = useState(false)
  const [currentUrl, setCurrentUrl] = useState('')
  const webviewRef = useRef(null)
  backButtonHandler = () => {
    if (webviewRef.current) webviewRef.current.goBack()
  }
  
  frontButtonHandler = () => {
    if (webviewRef.current) webviewRef.current.goForward()
  }

  return (
    <>
      <StatusBar barStyle='dark-content' />
      <View style={styles.flexContainer}>
        <WebView 
        userAgent="Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.193 Mobile Safari/537.36"
        source={{ uri: 'https://www.google.co.in/search?q=restaurants+nearby&ct=ifl&cad=2:hungry&ei=IWHsX_aDGJK0swXew5HgBw&ved=0ahUKEwi2mN_oyfXtAhUS2qwKHd5hBHwQnRsIDg&rct=j' }}
        mixedContentMode = "compatibility"
          ref={webviewRef}
          onNavigationStateChange={navState => {
            setCanGoBack(navState.canGoBack)
            setCanGoForward(navState.canGoForward)
            setCurrentUrl(navState.url)
          }}
        />
        <View style={styles.tabBarContainer}>
          <TouchableOpacity onPress={backButtonHandler}>
            <Ionicons name="ios-arrow-back" size={32} color="white" />
          </TouchableOpacity>
          <TouchableOpacity onPress={frontButtonHandler}>
            <Ionicons name="ios-arrow-forward" size={32} color="white" />
          </TouchableOpacity>
        </View>
      </View>
    </>
  )
}

const styles = StyleSheet.create({
  flexContainer: {
    flex: 1,
    paddingTop:Constants.statusBarHeight
  },
  tabBarContainer: {
    padding: 10,
    flexDirection: 'row',
    justifyContent: 'space-around',
    backgroundColor: '#000000'
  },
  button: {
    color: 'white',
    fontSize: 20
  }
})

export default App

Edit: Can you please provide a modified version of App.js above as I have already read through the various help documentation and codes there.

Upvotes: 0

Views: 4389

Answers (2)

Muhammad Numan
Muhammad Numan

Reputation: 25423

Expo

you can use expo-web-browser because Apple wants is to have it clearly visible that it is an external URL.

Installation

expo install expo-web-browser

expo-web-browser provides access to the system's web browser and supports handling redirects. On iOS, it uses SFSafariViewController or SFAuthenticationSession, depending on the method you call, and on Android it uses ChromeCustomTabs. As of iOS 11, SFSafariViewController no longer shares cookies with Safari, so if you are using WebBrowser for authentication you will want to use WebBrowser.openAuthSessionAsync, and if you just want to open a webpage (such as your app privacy policy), then use WebBrowser.openBrowserAsync

Usage

https://snack.expo.io/@nomi9995/basic-webbrowser-usage

import React, { useState } from 'react';
import { Button, Text, View, StyleSheet } from 'react-native';
import * as WebBrowser from 'expo-web-browser';
import Constants from 'expo-constants';

export default function App() {
  const [result, setResult] = useState(null);

  const _handlePressButtonAsync = async () => {
    let result = await WebBrowser.openBrowserAsync('https://expo.io');
    setResult(result);
  };
  return (
    <View style={styles.container}>
      <Button title="Open WebBrowser" onPress={_handlePressButtonAsync} />
      <Text>{result && JSON.stringify(result)}</Text>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
    paddingTop: Constants.statusBarHeight,
    backgroundColor: '#ecf0f1',
  },
});

React Native

you can use the following library react-native-inappbrowser

follow the installation from the github page

import { Linking } from 'react-native'
import InAppBrowser from 'react-native-inappbrowser-reborn'

...
  async openLink() {
    try {
      const url = 'https://www.google.com'
      if (await InAppBrowser.isAvailable()) {
        const result = await InAppBrowser.open(url, {
          // iOS Properties
          dismissButtonStyle: 'cancel',
          preferredBarTintColor: '#453AA4',
          preferredControlTintColor: 'white',
          readerMode: false,
          animated: true,
          modalPresentationStyle: 'overFullScreen',
          modalTransitionStyle: 'partialCurl',
          modalEnabled: true,
          // Android Properties
          showTitle: true,
          toolbarColor: '#6200EE',
          secondaryToolbarColor: 'black',
          enableUrlBarHiding: true,
          enableDefaultShare: true,
          forceCloseOnRedirection: false,
          // Specify full animation resource identifier(package:anim/name)
          // or only resource name(in case of animation bundled with app).
          animations: {
            startEnter: 'slide_in_right',
            startExit: 'slide_out_left',
            endEnter: 'slide_in_left',
            endExit: 'slide_out_right'
          },
          headers: {
            'my-custom-header': 'my custom header value'
          },
          waitForRedirectDelay: 0
        })
        Alert.alert(JSON.stringify(result))
      }
      else Linking.openURL(url)
    } catch (error) {
      Alert.alert(error.message)
    }
  }
...

you can check the example app here

for expo it becomes little bit complicated please check the related tutorial by Medium

if you want reading mode in ios please refer this link

reader-mode-webview-component-for-react-native

Upvotes: 2

Lukasz
Lukasz

Reputation: 1842

You've embedded a webview. What Apple wants, is to have it clearly visible that it is an external URL.

There is what's called Safari UI View Controller on IOS, and Chrome Custom tabs on Android.

There are a couple of plugins out there, but I liked using this one: https://www.npmjs.com/package/react-native-inappbrowser-reborn

Upvotes: 1

Related Questions