I have a problem with expo-google-app-auth in Android. It's work perfectly fine with IOS.
After successful sign in in Android instead of redirect me back to my app LoggedInPage component, I'm again in LoginPage component. I think it's because Android opens application again and I'm losing the state, so I'm also losing the states from login and I have to sign in again...
In IOS it just sign me in an redirecting to LoggedInPage component perfectly..
import React, { useState } from "react";
import * as Google from "expo-google-app-auth";
import { StyleSheet, Text, View, Image, Button } from "react-native";
export default function App() {
const [signedIn, setSignIn] = useState(false);
const [name, setName] = useState("");
const [photoUrl, setPhotoUrl] = useState("");
signIn = async () => {
try {
console.log("Sign in 1");
const result = await Google.logInAsync({
androidClientId:
“<< android client id >>apps.googleusercontent.com",
iosClientId:
“<< iOS client id >>.apps.googleusercontent.com",
scopes: ["profile", "email"]
});
console.log("Sign in 2");
console.log("Result: ", result);
if (result.type === "success") {
setSignIn(true);
setName(result.user.name);
setPhotoUrl(result.user.photoUrl);
return result.accessToken;
} else {
return { cancelled: true };
}
} catch (e) {
return { error: true };
}
};
const LoginPage = () => {
console.log("Inside LoginPage");
return (
<View>
<Text style={styles.header}>Sign In With Google</Text>
<Button title="Sign in with Google" onPress={() => signIn()} />
</View>
);
};
const LoggedInPage = () => {
return (
<View style={styles.container}>
<Text style={styles.header}>Welcome:{name}</Text>
<Image style={styles.image} source={{ uri: photoUrl }} />
</View>
);
};
console.log("SignedIn: ", signedIn);
return (
<View style={styles.container}>
{signedIn ? <LoggedInPage /> : <LoginPage />}
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
alignItems: "center",
justifyContent: "center"
},
header: {
fontSize: 25
},
image: {
marginTop: 15,
width: 150,
height: 150,
borderColor: "rgba(0,0,0,0.2)",
borderWidth: 3,
borderRadius: 150
}
});
Any ideas/guidance how should I fix my app in Android ?
You need to add a redirectUrl:
const result = await Google.logInAsync({
androidClientId:
“<< android client id >>apps.googleusercontent.com",
iosClientId:
“<< iOS client id >>.apps.googleusercontent.com",
scopes: ["profile", "email"],
redirectUrl: "{Your Bundle ID (com.example.app)}:/oauth2redirect/google",
});
Related
I have implement an barcode scanner app by using react native when I use web to execute the program all the function are work perfectly it can pass the data to api and post to the server but when I try to use it on my android and iOS device it cannot post the data below is my code for scanner.js
import React, { useState, useEffect,Component,onMount} from 'react';
import { Text,TextInput, View, StyleSheet, Button } from 'react-native';
import { BarCodeScanner } from 'expo-barcode-scanner';
import {useNavigation} from'#react-navigation/native';
import {StatusBar} from 'expo-status-bar';
export default function Scanner () {
const [hasPermission, setHasPermission] = useState(null);
const [scanned, setScanned] = useState(false);
const [userid, setuserid] = useState('Not yet scanned')
const [currentDate, setCurrentDate] = useState('');
const navigation = useNavigation();
const askForCameraPermission = () => {
(async () => {
const { status } = await BarCodeScanner.requestPermissionsAsync();
setHasPermission(status === 'granted');
})()
}
// Request Camera Permission
useEffect(() => {
askForCameraPermission();
}, []);
useEffect(() => {
var date = new Date().getDate(); //Current Date
var month = new Date().getMonth() + 1; //Current Month
var year = new Date().getFullYear(); //Current Year
var hours = new Date().getHours(); //Current Hours
var min = new Date().getMinutes(); //Current Minutes
var sec = new Date().getSeconds(); //Current Seconds
setCurrentDate(
date + '/' + month + '/' + year
+ ' ' + hours + ':' + min + ':' + sec
);
}, []);
// What happens when we scan the bar code
const handleBarCodeScanned = ({ type, data }) => {
setScanned(true);
setuserid(data )
};
// Check permissions and return the screens
if (hasPermission === null) {
return (
<View style={styles.container}>
<Text>Requesting for camera permission</Text>
</View>)
}
if (hasPermission === false) {
return (
<View style={styles.container}>
<Text style={{ margin: 10 }}>No access to camera</Text>
<Button title={'Allow Camera'} onPress={() => askForCameraPermission()} />
</View>)
}
const Register = () => {
let InsertAPIURL = "https://localhost/api/insert.php";
let headers = {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Access-Control-Allow-Methods': 'POST, PUT, PATCH, GET, DELETE, OPTIONS',
'Access-Control-Allow-Headers': 'Origin, X-Api-Key, X-Requested-With, Content-Type, Accept, Authorization',
}
let Data = {
userid:userid,
};
fetch(InsertAPIURL, {
mode:'no-cors',
method: 'POST',
headers: headers,
body: JSON.stringify(Data)
})
try{
((response) =>response.json()),
((response)=>{
alert(response[0].Message);
})
}
catch{
((error) => {
alert("Error"+error);
})
} }
// Return the View
return (
<View style={styles.container}>
<View style={styles.barcodebox}>
<BarCodeScanner
onBarCodeScanned={scanned ? undefined : handleBarCodeScanned}
style={{ height: 400, width: 400 }} />
</View>
<Text style={styles.maintext}>{userid + '\n'+currentDate}
</Text>
{
scanned && <Button title={'Scan again?'} onPress={() => setScanned(false)} color='tomato' />
}
{
scanned && <Button title={'OK'} onPress={()=> navigation.navigate('Home',{userid},Register())} />
}
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
maintext: {
fontSize: 16,
margin: 20,
},
barcodebox: {
alignItems: 'center',
justifyContent: 'center',
height: 300,
width: 300,
overflow: 'hidden',
borderRadius: 30,
backgroundColor: 'tomato'
}
});
I have make a research on other source they said that change the apiurl to http://10.0.2.2 instead of localhost host to made it function on android device but after I tried this method it also cannot solve the issue. this is my first react native project and I really hang on this part a few day already hope u guys help thanks in advance
You need to provide your ip address instead of the localhost, you can find it by doing ifconfig on linux/Mac and ipconfig on windows.
So you have something like this: 192.0.0.1:3000/yoururl instead of localhost:3000/yoururl
This is only needed if you want to test on a real device which is connected to your computer.
I am using react-native-call-detection package to save incoming call number (and send it on server later), I also want to reject/answer the incoming call based on the pressed button (based on server response later).
what package should I use to do it? I just found react-native-call-keep but all examples gave fake phone number to the functons and I don't know how to use its functions or how to get my call uuid.I just know there is reject/answer call function and I should call addEventListener functions before calling functions.
here is my current code:
import React, {useEffect, useState} from 'react';
import RNCallKeep from 'react-native-callkeep';
import {
View,
Text,
StyleSheet,
TouchableOpacity,
TouchableHighlight,
PermissionsAndroid,
} from 'react-native';
import CallDetectorManager from 'react-native-call-detection';
import RNCallKeep from 'react-native-callkeep';
export default class MasterScreen extends React.Component {
constructor(props) {
super(props);
this.state = {
featureOn: false,
incoming: false,
number: null,
};
}
componentDidMount() {
this.askPermission();
this.startListenerTapped();
this.setupCallKeep();
}
setupCallKeep() {
const options = {
android: {
alertTitle: 'Permissions Required',
alertDescription:
'This application needs to access your phone calling accounts to make calls',
cancelButton: 'Cancel',
okButton: 'ok',
imageName: 'ic_launcher',
additionalPermissions: [PermissionsAndroid.PERMISSIONS.READ_CONTACTS],
},
};
try {
RNCallKeep.setup(options);
RNCallKeep.setAvailable(true); // Only used for Android, see doc above.
} catch (err) {
console.error('initializeCallKeep error:', err.message);
}
}
askPermission = async () => {
try {
const permissions = await PermissionsAndroid.requestMultiple([
PermissionsAndroid.PERMISSIONS.READ_CALL_LOG,
PermissionsAndroid.PERMISSIONS.READ_PHONE_STATE,
]);
console.log('Permissions are:', permissions);
} catch (err) {
console.warn(err);
}
};
startListenerTapped = () => {
this.setState({featureOn: true});
this.callDetector = new CallDetectorManager(
(event, phoneNumber) => {
console.log(event);
if (event === 'Disconnected') {
this.setState({incoming: false, number: null});
} else if (event === 'Incoming') {
this.setState({incoming: true, number: phoneNumber});
} else if (event === 'Offhook') {
this.setState({incoming: true, number: phoneNumber});
} else if (event === 'Missed') {
this.setState({incoming: false, number: null});
}
},
true,
() => {},
{
title: 'Phone State Permission',
message:
'This app needs access to your phone state in order to react and/or to adapt to incoming calls.',
},
);
};
stopListenerTapped = () => {
this.setState({featureOn: false});
this.callDetector && this.callDetector.dispose();
};
render() {
return (
<View style={styles.body}>
<Text>incoming call number: {this.state.number}</Text>
<TouchableOpacity
onPress={/*what to do */} style={{
width: 200,
height: 200,
justifyContent: 'center',
}}><Text>answer</Text></TouchableOpacity>
<TouchableOpacity
onPress={/*what to do */} style={{
width: 200,
height: 200,
justifyContent: 'center',
}}>
<Text>reject</Text>
</TouchableOpacity>
</View>
);
}
}
const styles = StyleSheet.create({
body: {
backgroundColor: 'honeydew',
justifyContent: 'center',
alignItems: 'center',
flex: 1,
},
text: {
padding: 20,
fontSize: 20,
},
button: {},
});`
Use RNCallKeep.rejectCall. Like so
<TouchableOpacity
onPr ess={() => RNCallKeep.rejectCall(uuid)}
st yle={{
width: 200,
height: 200,
justifyContent: 'center',
}}
>
<Text>reject</Text>
</TouchableOpacity>
How to open the default Contact app in react native using Expo?
my requirements are:
Display a button to open the contact book on home screen.
On clicking the button, open the list of contacts in user's phone.
On contact list, each contact item should display the contact's profile picture, full name and the number/type of number(Home/work)
Add a search bar that will allow the user to search contacts by name
Once the user selects a contact, go back to home screen and display the chosen contact's phone number in a text field(not as an alert/toast).
If a contact has multiple phone numbers, allow the user to pick only one phone number.
import React, { useEffect, useState } from "react";
import {
StyleSheet,
View,
Text,
TextInput,
FlatList,
ActivityIndicator,
} from "react-native";
import * as Contacts from "expo-contacts";
export default function App() {
const [allcontacts, setcontact] = useState([]); //say set main state
const [allcontactsfilter, setcontactfilter] = useState([]); // filter state
const [searchcontact, setsearchcontact] = useState("");
const [loading, setloading] = useState(false);
console.log(searchcontact);
useEffect(() => {
(async () => {
const { status } = await Contacts.requestPermissionsAsync();
if (status === "granted") {
const { data } = await Contacts.getContactsAsync({
fields: [
Contacts.Fields.PhoneNumbers,
// Contacts.Fields.Emails
],
});
// console.log("collectio object", data);
if (data.length > 0) {
// console.log("contact hellos", data);
setcontact(data);
setting same data in two-state help to manipulate state when we do filtering
process
setcontactfilter(data);
setloading(false);
}
}
})();
setloading(true);
}, []);
filter function
const filtercontacts = (e) => {
const filtervalue = allcontactsfilter.filter((contact) => { <-- look here at
allcontactsfilter
let lowercase = `${contact.firstName} ${contact.lastName}`.toLowerCase();
let searchlowercase = e.toLowerCase();
return lowercase.indexOf(searchlowercase) > -1;
});
setsearchcontact(setcontact(filtervalue));
};
return (
<View style={styles.container}>
<TextInput
style={{
backgroundColor: "#D5D5D5",
height: 40,
width: "90%",
borderBottomWidth: 0.3,
borderBottomColor: "#ddd",
}}
placeholder="search"
value={searchcontact}
onChangeText={filtercontacts}
/>
{loading ? (
<View>
<ActivityIndicator size={35} color="green" />
</View>
) : null}
<FlatList
data={allcontacts}
keyExtractor={(item, index) => index.toString()}
renderItem={({ item }) => (
<View style={{ minHeight: 70, padding: 5 }}>
<Text>
{/* {
("inside flatlist>>>,....",
console.log(
item.phoneNumbers == undefined || null
? []
: item.phoneNumbers[0]?.number
))
} */}
{item?.firstName == null
? "please update name in your phone contact book"
: item.firstName}
{item?.lastName == null ? null : item.lastName}
</Text>
<Text style={{ color: "red" }}>
{item.phoneNumbers == undefined || null
? []
: item.phoneNumbers[0]?.number}
</Text>
</View>
)}
ListEmptyComponent={() => (
<Text style={{ fontSize: 20, marginVertical: 40 }}>No contact </Text>
)}
/>
{/* {console.log("okstate..", allcontacts)} */}
<Text>Contacts Module Example </Text>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
alignItems: "center",
justifyContent: "center",
},
});
apply style according to your need.
I’m trying to make a prototype application that over and over
1- record a video with the camera for x seconds
2- displays this video
For this I use the components Camera from expo-camera and Video from expo-av
For this I have two views :
I use in my code the stateSequence property and the sequencer() function which displays alternately the view with the Camera component which films for x seconds , and the video view which allows me to display the video.
Sequencer() is triggered with setInterval( this.sequencer , 10000) found in the componentWillMount()
I can switch alternately from a View with the Camera component to a View with the Video component.
To record a video with the Camera component I use recordAsync(), but I get the following error:
Unhandled promise rejection: Error: Camera is not running
I’m using an android phone for my tests.
Can’t you help me
this is my code
import { StyleSheet, Text, View ,TouchableOpacity} from 'react-native';
import * as Permissions from 'expo-permissions';
import { Camera } from 'expo-camera';
import { Video } from 'expo-av';
import { Logs } from 'expo';
export default class SequenceViewer extends Component {
constructor(props) {
super(props);
this.state = {
stateSequence: "SHOOT ",
hasCameraPermission: null,
type: Camera.Constants.Type.front,
}
this.recordVideo = this.recordVideo.bind(this)
}
sequencer = () => {
if(this.state.stateSequence==="WATCH"){
this.setState({ stateSequence: "SHOOT",})
this.recordVideo(); // Error message Camera is not running
} else {
this.setState({stateSequence: "WATCH"})
}
}
async componentWillMount() {
let rollStatus = await Permissions.askAsync(Permissions.CAMERA_ROLL);
let cameraResponse = await Permissions.askAsync(Permissions.CAMERA)
if (rollStatus.status=='granted'){
if (cameraResponse.status == 'granted' ){
let audioResponse = await Permissions.askAsync(Permissions.AUDIO_RECORDING);
if (audioResponse.status == 'granted'){
this.setState({ permissionsGranted: true });
setInterval( this.sequencer , 10000);
}
}
}
}
recordVideo = async () => {
if(this.state.cameraIsRecording){
this.setState({cameraIsRecording:false})
this.camera.stopRecording();
}
else {
this.setState({cameraIsRecording:true})
if (this.camera) {
let record = await this.camera.recordAsync(quality='480p',maxDuration=5,mute=true).then( data =>{
this.setState( {recVideoUri :data.uri})
})
}
}
};
render() {
const { hasCameraPermission } = this.state
if(this.state.stateSequence=="WATCH")
{
return(
<View style={styles.container}>
<Video
source={{ uri:this.state.recVideoUri }}
rate={1.0}
volume={1.0}
isMuted={false}
resizeMode="cover"
shouldPlay
isLooping
style={{ width: 300, height: 300 }}
ref={(ref) => { this.player = ref }}
/>
</View>
)
} else
{
return(
<View style={{ flex: 1 }}>
<Camera style={{ flex: 1 }} type={this.state.type} ref={ref => {this.camera = ref; }}></Camera>
</View>
)
}
}
}
const styles = StyleSheet.create({
viewerText: {
fontSize: 20,
fontWeight: 'bold',
},
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
Thank you
I had the same problem, my solution was by default camera type have to be "back" and you could change to "front" by:
componentDidMount = () => {
this.props.navigation.addListener('didFocus', async () => {
await setTimeout(() => {
this.setState({ cameraType: Camera.Constants.Type.front })
}, 100)
});
}
I was getting the "Camera is not running" error when i changed screens. So for functional components instead of withNavigationFocus(Camera) use this method:
import { useIsFocused } from '#react-navigation/native';
function MyComponent() {
const isFocused = useIsFocused()
return (
<View>
{ isFocused && <RNCamera /> }
</View>
)
}
I am developing an app That contain an image uploader. I found some code on internet that can upload image. And it worked partially. Which means When i press the choose image button, it opens gallery and i am able to select and crop image. And after cropping when i select ok nothing happen. It just show the image and its not uploading to the firebase cloud. Here is my code.
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
Button,
Image,
ActivityIndicator,
TouchableOpacity
} from 'react-native';
import * as firebase from 'firebase';
import RNFetchBlob from 'react-native-fetch-blob';
import ImagePicker from 'react-native-image-crop-picker';
export default class RNF extends Component {
constructor (props) {
super(props);
this.state = {
loading: false,
dp: null
};
}
openPicker () {
this.setState({ loading: true });
const Blob = RNFetchBlob.polyfill.Blob;
const fs = RNFetchBlob.fs;
window.XMLHttpRequest = RNFetchBlob.polyfill.XMLHttpRequest;
window.Blob = Blob;
// const { uid } = this.state.user
const uid = '12345';
ImagePicker.openPicker({
width: 300,
height: 300,
cropping: true,
mediaType: 'photo'
}).then(image => {
const imagePath = image.path;
let uploadBlob = null;
const imageRef = firebase.storage().ref(uid).child('dp.jpg');
let mime = 'image/jpg';
fs.readFile(imagePath, 'base64')
.then((data) => {
// console.log(data);
return Blob.build(data, { type: `${mime};BASE64` });
})
.then((blob) => {
uploadBlob = blob;
return imageRef.put(blob, { contentType: mime });
})
.then(() => {
uploadBlob.close();
return imageRef.getDownloadURL();
})
.then((url) => {
let userData = {};
// userData[dpNo] = url
// firebase.database().ref('users').child(uid).update({ ...userData})
let obj = {};
obj['loading'] = false;
obj['dp'] = url;
this.setState(obj);
})
.catch((error) => {
console.log(error);
});
})
.catch((error) => {
console.log(error);
});
}
render () {
const dpr = this.state.dp ? (<TouchableOpacity onPress={ () => this.openPicker() }><Image
style={{ width: 100, height: 100, margin: 5 }}
source={{ uri: this.state.dp }}
/></TouchableOpacity>) : (<Button
onPress={ () => this.openPicker() }
title={ 'Change Picture' }
/>);
const dps = this.state.loading ? <ActivityIndicator animating={this.state.loading} /> : (<View style={styles.container}>
<View style={{ flexDirection: 'row' }}>
{ dpr }
</View>
</View>);
return (
<View style={styles.container}>
{ dps }
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF'
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10
},
instructions: {
textAlign: 'center',
color: '#333333',
marginBottom: 5
}
});
AppRegistry.registerComponent('RNF', () => RNF);