Open react native expo app external links outside the app - ios

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.

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

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

Related

React Native NOT rendering data from database on IOS

I have problem with render data on IOS Simulator. Render is work properly on website, but on IOS I still got stuck on "Loading.." text.
Here is my code:
import React from 'react'
import { useState } from 'react';
import { useEffect } from 'react';
import { SafeAreaView, Text, View, StyleSheet, Image, Alert } from 'react-native';
import { Card } from 'react-native-paper'
import firebase from 'firebase'
import Button from '../components/Button'
import Background from '../components/Background'
import TopBar from '../components/TopBar'
export default function HomeScreen({ navigation }) {
const [data, setData] = useState([])
const sampleData = [{id:0, title:"One"}, {id:1, title: "Two"}]
useEffect(() =>
{
const donorsData = [];
firebase.database()
.ref("testdb")
.orderByChild("isDonor")
.equalTo(true)
.once("value")
.then((results) => {
results.forEach((snapshot) => {
donorsData.push(snapshot.val());
});
setData(donorsData);
});
}, [])
const card = data.length > 0
? data.map(item =>
{
return <Card key={item.uid} style={{ marginBottom: 20, borderRadius: 10, }}>
<Text>{item.name}</Text>
<Text>{item.description}</Text>
<Image src={item.photo}></Image>
</Card>
})
: <Text>Loading...</Text>
return (
<View style={styles.container}>
{card}
</View>
);
}
On website is everything ok Website Screen
But on IOS Simulator I got only Loading
IOS Screen
I tried a lot of solutions found here, but no one works with this case. I think is probably because iOS doesn't have data? When I put console log at to top of return, I got nothing.
This might be a race condition error. You shouldn't rely on the data being fetched within 1500ms.
If that doesn't work. Make sure your result from firebase is correct.
Maybe something like this?
const [data, setData] = useState([])
const fetchDonorData = () => {
firebase.database()
.ref("testdb")
.orderByChild("isDonor")
.equalTo(true)
.once("value")
.then((results) => {
console.log({result}) //Make sure the data looks the way you want it
const mappedResult = results?.map(snapshot => snapshot.val())
setData(mappedResult)
})
}
useEffect(() => {
fetchDonorData()
}, [])
const renderItem = ({item}) =>
<Card style={{ marginBottom: 20, borderRadius: 10, }}>
<Text>{item.name}</Text>
<Text>{item.description}</Text>
<Image src={item.photo}></Image>
</Card>
return (
<View style={styles.container}>
<FlatList
data={data}
renderItem={renderItem}
keyExtractor={({item}) => item.uid}
ListEmptyComponent={<Text>Loading...</Text>}
/>
</View>
)

How do I extend the current theme to my components in expo react-native?

I'm trying to implement themes (dark | light) in my expo react-native app. I've been reading their documentation on the dark and light themes on the expo page, and that works inside App.js. However, whenever I declare a component and import it in App.js, it won't work. My thought process is trying to "extend" the current theme to my component.
Here's the App.js code:
import { StatusBar } from 'expo-status-bar';
import React from 'react';
import { StyleSheet, Text, View, useColorScheme } from 'react-native';
//import firebase + config
import firebaseConfig from './config'
import firebase from 'firebase'
//initialize firebase application
if(!firebase.apps.length){
firebase.initializeApp(firebaseConfig)
} else{
firebase.app()
}
//import screens
import Overview from './screens/Overview'
export default function App() {
const colorScheme = useColorScheme();
const themeTextStyle = colorScheme === 'light' ? styles.lightThemeText : styles.darkThemeText;
const themeContainerStyle = colorScheme === 'light' ? styles.lightContainer : styles.darkContainer;
return (
<View style={[styles.container, themeContainerStyle]}>
<Overview />
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
lightContainer: {
backgroundColor: '#fff',
},
darkContainer: {
backgroundColor: '#101010',
},
lightThemeText: {
color: '#000000',
},
darkThemeText: {
color: '#ffffff',
},
});
And here's my simple component:
import React from 'react'
import {View, Text, useColorScheme} from 'react-native'
export default class App extends React.Component{
render(){
return(
<View>
<Text>OverView</Text>
</View>
)
}
}
All I'm trying to do is get that Overview component to follow the theme rules instead of needing to declare the style that's already been declared in App.js.
Now it's not reflected in the code, but I did try a lot of stuff before posting this question.
Firstly, install react-native-appearance from here
Create a folder called context where your App.js is located then inside it create a file called ThemeContext.js inside which will look like this
import React from "react";
const ThemeContext = React.createContext();
export default ThemeContext;
Then your App.js should look like this
import React from 'react';
import { StatusBar } from 'expo-status-bar';
import { StyleSheet, Text, View } from 'react-native';
import { AppearanceProvider, useColorScheme } from 'react-native-appearance';
//import firebase + config
import firebaseConfig from './config';
import firebase from 'firebase';
import ThemeContext from './context/ThemeContext'; // Imported Here
//initialize firebase application
if (!firebase.apps.length) {
firebase.initializeApp(firebaseConfig);
} else {
firebase.app();
}
//import screens
import Overview from './screens/Overview';
export default function App() {
const colorScheme = useColorScheme();
const themeValue =
colorScheme === 'light' ? styles.lightThemeText : styles.darkThemeText;
const themeContainerStyle =
colorScheme === 'light' ? styles.lightContainer : styles.darkContainer;
return (
<AppearanceProvider>
<ThemeContext.Provider value={themeValue}> // Wrapped Here
<View style={[styles.container, themeContainerStyle]}>
<Overview />
</View>
</ThemeContext.Provider>
</AppearanceProvider>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
lightContainer: {
backgroundColor: '#fff',
},
darkContainer: {
backgroundColor: '#101010',
},
lightThemeText: {
color: '#000000',
},
darkThemeText: {
color: '#ffffff',
},
});
Your Overview.js should look like this
import React from 'react';
import { View, Text } from 'react-native';
import ThemeContext from '../context/ThemeContext';
function Overview() {
const themeContext = React.useContext(ThemeContext);
console.log(themeContext); // You will get styles logged into the console here
return (
<View>
<Text>OverView</Text>
</View>
);
}
export default Overview;

Open Measure App (iOS) in your React Native App using a button [Expo]

I am trying to open the Measure iPhone App inside my react native app. I have tried to use linking but as mentioned in this stackoverflow question, Measure does not support URL scheme or Deep Linking. Is there any other way to open the Measure App inside or be redirected to Measure App from my App in react native?
import React, { Component } from 'react';
import { Button, Linking, View, StyleSheet } from 'react-native';
import Constants from 'expo-constants';
export default class App extends Component {
render() {
return (
<View style={styles.container}>
<Button
title="Open Measure App"
onPress={this._handleOpenWithLinking}
style={styles.button}
/>
</View>
);
}
_handleOpenWithLinking = () => {
// Should open the Measure App
// This does not work as mentioned - Linking.openURL("measure://")
};
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
},
button: {
marginVertical: 10,
},
});

Rendering JSON data in react native

I'm currently using my api to render all posts in JSON to react native. But I keep getting this undefined error. And sometimes the data just wont render. Can anyone give me any help on rendering this data in react native? And explain to me what i'm doing wrong? I'm pretty new with JSON. Thanks :)
Here is my JSON:
{"data":[{"id":"1","type":"posts","links":{"self":"https://example.com/posts/1"},"attributes":{"title":"Laughter Post","context":{}},"relationships":{"user":{"links":{"self":"https://example.com/posts/1/relationships/user","related":"https://example.com/posts/1/user"}}}}]}
And here is my react native code:
import React, { Component } from "react";
import { FlatList, StyleSheet, Text, View } from "react-native";
export default class App extends Component {
state = {
data: []
};
componentWillMount() {
this.fetchData();
}
fetchData = async () => {
const response = await fetch("https://example.com/posts.json");
const json = await response.json();
this.setState({ data: json.data });
};
render() {
return (
<View style={styles.container}>
<FlatList
data={this.state.data}
keyExtractor={item => item.toString()}
renderItem={({ item }) =>
<Text>
{`${item.title}`}
</Text>}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
marginTop: 15,
flex: 1,
justifyContent: "center",
alignItems: "center",
backgroundColor: "#F5FCFF"
}
});
It seems you are accessing title directly from the root, but it is inside key attributes
It should be
{`${item. attributes.title}`}
Or else if you can tell us the exact error, we can help you more regarding this issue.

Super expression must either be null or a function, react native 0.26.3

I am a newbie in react native.
I have one similar problem in different projects. When I try to compile my project, I see this problem. Why this error is appear?
P.S. I am learning react-native by tutorials like a appcoda.com
Picture of my error
Featured.js
'use strict';
var React = require('react-native');
var{
StyleSheet,
View,
Text,
Component
} = React;
var styles = StyleSheet.create({
description:{
fontSize: 20,
backgroundColor: 'white'
},
container:{
flex: 1,
justifyContent: 'center',
alignItems: 'center'
}
});
class Featured extends Component{
render() {
return(
<View style = {styles.container}>
<Text style = {styles.description}>
Featured tab
</Text>
</View>
);
}
}
module.exports = Featured;
Change your import statement as below
import React, { Component } from 'react';
import {
StyleSheet,
View,
Text,
} from 'react-native';

Resources