I'm trying to ask for runtime permission in ReactNative, but I'm always getting a "Permission is null" error in device screen.
here is the code:
import React, {Component} from 'react';
import {Text, View, StyleSheet, TextInput, Button} from 'react-native';
import {PermissionsAndroid} from 'react-native';
export default class HomeScreen extends React.Component {
componentDidMount()
{
PermissionsAndroid.request(PermissionsAndroid.READ_PHONE_STATE)
}
render () {
return (
<View style={styles.container}>
<Text style={styles.paragraph}>Seja Bem vindo a BBTS!</Text>
<Text style={styles.paragraph}>
Matricula: {this.props.navigation.state.params.matricula}
</Text>
<Text style={styles.paragraph}>
Email: {this.props.navigation.state.params.email}
</Text>
<Text style={styles.paragraph}>
imei vem aqui
</Text>
</View>
);
}
}
I already put this on android manifest. My APi target is 26.
Any ideias?
Solution:
async requestPermission() {
try {
const granted = await PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.READ_PHONE_STATE)
if (granted === PermissionsAndroid.RESULTS.GRANTED) {
console.log("You can read the phone state")
} else {
console.log("permission denied")
}
} catch (err) {
console.warn(err)
}
}
componentDidMount()
{
this.requestPermission();
}
While you do need to handle the promise as #Daniel says the reason for the error is that your permissions request is incorrect, it should be:
PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.READ_PHONE_STATE)
The request() method returns a promise. You'll either need to async/await or .then()/.catch() and then check PermissionsAndroid.RESULTS.GRANTED. That may either fix your problem or help you debug.
Related
I have troubles having audio permissions to work on android build. It works fine in expo go, but not in android build.
In the given code, the permission for the camera is asked properly, but when accepted the permission for audio shows only for a fraction of a second and return a not granted status.
Once again, it works fine in expo go.
Is there anything i’m doing wrong ? do you have an idea on how to solve this ?
Thanks you very much community !
SDK Version: 41
Platforms(Android/iOS/web/all): Android (samsung A20e)
import {Camera} from 'expo-camera'
import {Audio} from 'expo-av';
export default () => {
return (
<View>
<Button
onPress={() => {
Camera.requestPermissionsAsync().then((status) => {
// audio permission request is only shown for half a second in build mode and is automatically denied permission
Audio.requestPermissionsAsync().then((status) => {
console.log('ok');
});
});
}}>
Test
</Button>
</View>
);
};
Use it like this
Working Example Here
import { Camera } from 'expo-camera';
import { Audio } from 'expo-av';
const GetPermissions = async () => {
try {
console.log('Requesting permissions..');
const CameraPerm = await Camera.requestPermissionsAsync();
if (CameraPerm.status === 'granted') {
console.log('Camera Permission Granted');
}
const AudioPerm = await Audio.requestPermissionsAsync();
if (AudioPerm.status === 'granted') {
console.log('Audio Permission Granted');
}
} catch (err) {
console.error('Failed to get permissions', err);
}
};
return (
<View style={styles.container}>
<Button title="Get Permissions" onPress={GetPermissions} />
</View>
);
Make sure all the imports are correct
be sure to have either both or none in your app.json
that was my problem !
I am trying to use the react-native-live-audio-stream library. However I get errors with the permission of the microphone.
I am following this exact link on how to set it up.
This is my recorder component:
import React from 'react';
import {TouchableOpacity, View} from 'react-native';
import LiveAudioStream from 'react-native-live-audio-stream';
export default function Recorder() {
const options = {
sampleRate: 32000, // default is 44100 but 32000 is adequate for accurate voice recognition
channels: 1, // 1 or 2, default 1
bitsPerSample: 16, // 8 or 16, default 16
audioSource: 6, // android only (see below)
};
LiveAudioStream.init(options);
LiveAudioStream.on('data', (data) => {
// base64-encoded audio data chunks
});
return (
<View>
<TouchableOpacity onClick={LiveAudioStream.start()}>
<Text>Start recording!</Text>
</TouchableOpacity>
</View>
);
}
The error I get is:
startRecording() called on an uninitialized AudioRecord.
So I start investigating the permission thing... This is what I've got so far:
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="Manifest.permission.RECORD_AUDIO"/>
in AndroidManifest.xml
By adding a request for the microphone like this:
const requestMicrophone = async () =>{
if (ContextCompat.checkSelfPermission(getActivity(),
Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(getActivity(),
new String[]{Manifest.permission.RECORD_AUDIO},
REQUEST_MICROPHONE);
}
I get the error of:
[![ActivityCompat.requestPermissions(getActivity(),new String\[\]{Manifest.permission.RECORD_AUDIO},
REQUEST_MICROPHONE]2]2
Any ideas on how to fix this?
EDIT:
I fixed the error! The audio related things in the recorder needs to be put in a function which is called by starting the recording.
Try this code for taking permission in android:
import {PermissionsAndroid, Platform} from 'react-native';
.....
const requestMicrophone = async () => { //replace your function with this code.
if (Platform.OS === 'android') {
try {
const granted = await PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.RECORD_AUDIO,
{
title: 'Permissions for record audio',
message: 'Give permission to your device to record audio',
buttonPositive: 'ok',
},
);
if (granted === PermissionsAndroid.RESULTS.GRANTED) {
console.log('permission granted');
} else {
console.log('permission denied');
return;
}
} catch (err) {
console.warn(err);
return;
}
}
}
First you are using onClick event its react event not react native you should switch to onPress event also you are invoking LiveAudioStream.start() with each render by using start()
<View>
<TouchableOpacity onClick={LiveAudioStream.start()}>
<Text>Start recording!</Text>
</TouchableOpacity>
</View>
//edited
<View>
<TouchableOpacity onPress={()=>LiveAudioStream.start}>
<Text>Start recording!</Text>
</TouchableOpacity>
</View>```
I am using this library in RN to implement fingerprint scanning react-native-fingerprint-scanner and its working fine with scanning but I would like to implement a function that registers a new fingerprint for this app.
I was absolutely not able to find it anything on the internet related to this.
Here is the code that I have implemented so far:
import React, { Component } from 'react';
import {
Alert,
Image,
Text,
TouchableOpacity,
View,
ViewPropTypes
} from 'react-native';
import FingerprintScanner from 'react-native-fingerprint-scanner';
import PropTypes from 'prop-types';
import ShakingText from './ShakingText.component';
import styles from './FingerprintPopup.component.styles';
class FingerprintPopup extends Component {
constructor(props) {
super(props);
this.state = { errorMessage: undefined };
}
componentDidMount() {
FingerprintScanner
.authenticate({ onAttempt: this.handleAuthenticationAttempted })
.then(() => {
this.props.handlePopupDismissed();
Alert.alert('Fingerprint Authentication', 'Authenticated successfully');
})
.catch((error) => {
this.setState({ errorMessage: error.message });
this.description.shake();
});
}
componentWillUnmount() {
FingerprintScanner.release();
}
handleAuthenticationAttempted = (error) => {
this.setState({ errorMessage: error.message });
this.description.shake();
};
render() {
const { errorMessage } = this.state;
const { style, handlePopupDismissed } = this.props;
return (
<View style={styles.container}>
<View style={[styles.contentContainer, style]}>
<Image
style={styles.logo}
source={require('../pictures/finger_print.png')}
/>
<Text style={styles.heading}>
Fingerprint{'\n'}Authentication
</Text>
<ShakingText
ref={(instance) => { this.description = instance; }}
style={styles.description(!!errorMessage)}>
{errorMessage || 'Scan your fingerprint on the\ndevice scanner to continue'}
</ShakingText>
<TouchableOpacity
style={styles.buttonContainer}
onPress={handlePopupDismissed}
>
<Text style={styles.buttonText}>
BACK TO MAIN
</Text>
</TouchableOpacity>
</View>
</View>
);
}
}
FingerprintPopup.propTypes = {
style: ViewPropTypes.style,
handlePopupDismissed: PropTypes.func.isRequired,
};
export default FingerprintPopup;
EDIT: Or at least I would like to prompt the user to set Fingerprint if they already don't have any finger enrolled in the phone.
I have found out that none of the OS (Android, iOS) will give you access to the keychain that's holding the credentials, for security reasons.
However, I can use the same that's stored in the device's memory by the user to access my app same as other apps if they have the fingerprint feature implemented.
All in all, you cant enrol a new unique fingerprint ONLY for your app!
In this project I want to set the state of the userType using the data that I retrieved from the firebase database. fetching from the firebase is working correctly but I cant set the state of userType from there
import React from 'react';
import { StyleSheet, Text, View, TouchableOpacity, TextInput, Image } from 'react-native';
import * as firebase from 'firebase';
export default class Home extends React.Component {
constructor(props){
super(props)
this.state=({
userId:firebase.auth().currentUser.uid,
userType:'f'
})
}
componentDidMount() {
this.readUserData();
};
readUserData=()=> {
userstype= 'users/'+ this.state.userId + '/userType'
firebase.database().ref(userstype).on('value', function (snapshot) {
this.state=({userType:snapshot.val()})
});
alert(this.state.userType)
}
render() {
return (
<View style={styles.container}>
<Text style={styles.titleText}>Taams</Text>
<Text style={styles.edition}>Developer's Edition</Text>
<Text style={styles.titleText}>Home</Text>
<Text>Alpha 0.0.0.1</Text>
</View>
To set the state, please try to do as following instead of this.state=({userType:snapshot.val()}):
this.setState({ userType:snapshot.val() });
Only use this.state ={} in the constructor. Everywhere else it should be.
this.setState({})
so change
firebase.database().ref(userstype).on('value', function (snapshot) {
this.state=({userType:snapshot.val()})
});
to
firebase.database().ref(userstype).on('value', function (snapshot) {
this.setState({userType:snapshot.val()})
});
firebase.database().ref(userstype).on('value', (snapshot) => {
this.setState({userType: snapshot.val()})
});
This might be a context issue. Without binding the anonymous function, you'll lose the original context. Try using an ES6's arrow function and this.setState({})
I am newbie in ReactNative. ( I am very familiar with Raw Android)
Yesterday when I was using AsyncStorage ( incorrectly I think) , I met a problem that the View kept re-rendering every n millionseconds.
my code:
import React, { Component} from 'react';
import {Image, Platform, StyleSheet, Text, View, Button} from 'react-native'
import { AsyncStorage } from "react-native"
export default class StorageDemo extends Component{
constructor(props){
super(props)
AsyncStorage.setItem("visitTimes", 100)
this.state = {
isLoaded: false,
visitTimes: 0
}
}
readData = async () => {
try{
const result = await AsyncStorage.getItem("visitTimes")
this.setState(
{
visitTimes: result,
isLoaded: true
}
)
console.info("== loaded, this.state: ")
}catch(error){
console.error(error)
}
}
render() {
this.readData()
if(this.state.isLoaded){
return(
<View>
<Text>Loaded! </Text>
</View>
)
}else{
return(
<View>
<Text>Loading... </Text>
</View>
)
}
}
}
Also I opened a logcat window to check the log, I was shocked by the log: it kept re-rendering the View every 10 ms.
My environment:
Android SDK: 27
Windows
ReactNative 0.55
Device: VIVO Y67A ( Android 6.0 , 4G RAM)
code could be found here: https://github.com/sg552/react_native_lesson_demo/blob/master/screens/StorageDemo.js
I know my code is not correct (using async, await) , so my question is:
How to read from AsyncStorage and render it to page? How to correct my code?
thanks a lot!
Okay, so the problem is that you are calling your func this.readData() inside the render, and that function itself is calling setState which whenever is called, changes the state, which triggers a re-render on the component. So in this situation you have caused an infinite loop in the code, because setState calls render, which in turn calls setState again and you run out of memory.
To fix this quickly, you can remove the function call from your render, and add it to a button, so its only called when you want it to. Something like this:
import React, { Component} from 'react';
import {Image, Platform, StyleSheet, Text, View, Button} from 'react-native'
import { AsyncStorage } from "react-native"
export default class StorageDemo extends Component{
constructor(props){
super(props)
this.state = {
isLoaded: false,
visitTimes: 0
}
}
readData = async () => {
try{
const result = await AsyncStorage.getItem("visitTimes")
this.setState(
{
visitTimes: result,
isLoaded: true
}
)
console.info("== loaded, this.state: ")
}catch(error){
console.error(error)
}
}
render() {
if(this.state.isLoaded){
return(
<View>
<Text>Loaded! {this.state.visitTimes} </Text>
<Button
onPress={() => {
AsyncStorage.setItem("visitTimes", "100")
this.setState({isLoaded: false})
}}
title="Set Storage Item"
/>
</View>
)
}else{
return(
<View>
<Button
onPress={this.readData}
title="Load from async storage"></Button>
</View>
)
}
}
}
Try this and this should give you the value from localStorage!