How do I request multiple permissions at once in react native - permissions

I'd like to request permissions on one page instead of waiting for each particular situation. However, I do not want multiple popups. Is there a way to ask for permissions with a single popup/modal.
On the android side I found this post and this, which look promising, but I have yet to find something for iOS.

In Android
First add permissions in to the AndroidManifest.xml file and then
if (Platform.OS === 'android') {
PermissionsAndroid.requestMultiple(
[PermissionsAndroid.PERMISSIONS.CAMERA,
PermissionsAndroid.PERMISSIONS.READ_CONTACTS,
PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION,
PermissionsAndroid.PERMISSIONS.ACCESS_COARSE_LOCATION,
PermissionsAndroid.PERMISSIONS.READ_EXTERNAL_STORAGE,
PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE]
).then((result) => {
if (result['android.permission.ACCESS_COARSE_LOCATION']
&& result['android.permission.CAMERA']
&& result['android.permission.READ_CONTACTS']
&& result['android.permission.ACCESS_FINE_LOCATION']
&& result['android.permission.READ_EXTERNAL_STORAGE']
&& result['android.permission.WRITE_EXTERNAL_STORAGE'] === 'granted') {
this.setState({
permissionsGranted: true
});
} else if (result['android.permission.ACCESS_COARSE_LOCATION']
|| result['android.permission.CAMERA']
|| result['android.permission.READ_CONTACTS']
|| result['android.permission.ACCESS_FINE_LOCATION']
|| result['android.permission.READ_EXTERNAL_STORAGE']
|| result['android.permission.WRITE_EXTERNAL_STORAGE'] === 'never_ask_again') {
this.refs.toast.show('Please Go into Settings -> Applications -> APP_NAME -> Permissions and Allow permissions to continue');
}
});
}
In iOS
In the info section of your project on XCode
Add the permissions and the description
say - ex: Privacy - Contacts Usage Description
then,
Permissions.request('photo').then(response => {
if (response === 'authorized') {
iPhotoPermission = true;
}
Permissions.request('contact').then(response => {
if (response === 'authorized') {
iPhotoPermission = true;
}
});
});

Makes sure you also add respective permissions in manifest file as well.
export async function GetAllPermissions() {
try {
if (Platform.OS === "android") {
const userResponse = await PermissionsAndroid.requestMultiple([
PermissionsAndroid.PERMISSIONS.READ_CONTACTS,
PermissionsAndroid.PERMISSIONS.CALL_PHONE
]);
return userResponse;
}
} catch (err) {
Warning(err);
}
return null;
}

To request multiple permissions I will suggest you to use npm module as its saves time and easy to setup and most important you don't have to worry about the platforms :)
Installation
npm install --save react-native-permissions
Usage
import Permissions from 'react-native-permissions'
// Check the status of multiple permissions
_checkCameraAndPhotos = () => {
Permissions.checkMultiple(['camera', 'photo']).then(response => {
//response is an object mapping type to permission
this.setState({
cameraPermission: response.camera,
photoPermission: response.photo,
})
})
}
Don't forget to add permissions to AndroidManifest.xml for android and Info.plist for iOS (Xcode >= 8).

First add your permissions to "android/app/src/main/AndroidManifest.xml" file. You can use npm module in order to achieve your goal.
npm install --save react-native-permissions
After installation, you can use checkMultiple function to ask multiple permissions. Following code illustrates how to ask permission for ANDROID.CAMERA and ANDROID.READ_EXTERNAL_STORAGE :
checkMultiple([
PERMISSIONS.ANDROID.CAMERA,
PERMISSIONS.ANDROID.READ_EXTERNAL_STORAGE,
]).then(result => {
console.log(result);
});
The result will be an object like this
{"android.permission.CAMERA": "denied", "android.permission.READ_EXTERNAL_STORAGE": "denied"}
To handle this result, you can use this basic code example
checkPermissions = () => {
if (Platform.OS !== 'android') {
return;
}
checkMultiple([
PERMISSIONS.ANDROID.CAMERA,
PERMISSIONS.ANDROID.READ_EXTERNAL_STORAGE,
]).then(result => {
if (
!result ||
!result[PERMISSIONS.ANDROID.CAMERA] ||
!result[PERMISSIONS.ANDROID.READ_EXTERNAL_STORAGE]
) {
console.log('could not get any result. Please try later.');
}
if (
result[PERMISSIONS.ANDROID.CAMERA] === RESULTS.GRANTED &&
result[PERMISSIONS.ANDROID.READ_EXTERNAL_STORAGE] === RESULTS.GRANTED
) {
console.log('granted for both permissions');
// do smthing here
}
});
};

There is also a way to request multiple permissions at once using react-native-permissions package.
you can also implement your own conditions according to need, i am just writing a simple solution
requestMultiple will not ask again if permissions are already granted.
import { checkMultiple, requestMultiple, PERMISSIONS } from 'react-native-permissions';
const verifyPermissions = async () => {
let perm = [ PERMISSIONS.IOS.CAMERA, PERMISSIONS.IOS.PHOTO_LIBRARY ];
if (Platform.OS == 'android') {
perm = [ PERMISSIONS.ANDROID.CAMERA, PERMISSIONS.ANDROID.READ_EXTERNAL_STORAGE ];
}
let permissionStatuses = await requestMultiple(perm);
console.log('obj', permissionStatuses);
console.log('Camera', permissionStatuses[perm[0]]);
console.log('photo', permissionStatuses[[ perm[1] ]]);
const result = permissionStatuses[perm[0]];
if (result !== 'granted') {
Alert.alert('Insufficient permissions!', 'You need to grant camera and library access permissions to use this app.', [
{ text: 'Okay' }
]);
return false;
}
return true;
};

Related

Why app is not asking for requested location permission?

What im trying to do is to ask the user for location permission, and if the user doesn't allow the permission, cannot navigate to other screens.
I have used expo-location for this, and when I test the app locally, it asks me to allow or not allow the permission for the location, but when I generate an APK, to test it on android, it shows me the alert that I dont have the location permission, and when I go to the app setting to allow it manually, it says No permission requested
function requestLocationPermission() {
return Location.requestForegroundPermissionsAsync().then((handleResponse) => {
if (handleResponse.status === 'granted') {
setLocationPermission(handleResponse.status);
} else if (handleResponse.status !== 'granted') {
alert('Map/Gps needs the appropriate permissions.');
return Location.requestForegroundPermissionsAsync();
}
});
}
useEffect(() => {
requestLocationPermission();
buttonText();
}, [locationPermission]);
const confirm = () => {
if (locationPermission === "granted") {
navigation.navigate('CreateProfile',
} else {
requestLocationPermission();
}
};
So, in the APK it returns me: alert('Map/Gps needs the appropriate permissions.');
How can I fix this?

Can't import Contacts from 'react-native-contacts'

I have already tried to solve this problem using
react-native-contacts getAll return null,
react-native-contacts returns undefined.
But, unfortunately, I can't get success.
I've already run below shells:
npm install react-native-contacts --save
react-native link react-native-contacts
Here is my code =========
import Contacts from 'react-native-contacts';
componentDidMount() {
if(Platform.OS === 'ios'){
Contacts.getAll((err, contacts) => {
if (err) {
throw err;
}
// contacts returned
console.log("contacts => ", contacts);
})
}else if(Platform.OS === 'android'){
PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.READ_CONTACTS,
{
title: 'Contacts',
message: 'This app would like to view your contacts.'
}
).then(() => {
Contacts.getAll((err, contacts) => {
if (err === 'denied'){
// error
} else {
// contacts returned in Array
console.log("contacts => ", contacts);
}
})
})
}
}
======================================
Here is my result.
screen shoot my error terminal
My environment :
> expo --version
> 4.0.6
> node --version
> v14.15.0
> npm --version
> 6.14.8
As You Are Using Expo You Can Try Using The Contacts Module From Expo . The Documentation For Contacts https://docs.expo.io/versions/v32.0.0/sdk/contacts/ .
In Case You Want To Use react-native-contacts You must eject expo and continue with react-native-cli
import { Contacts } from 'expo';
const { data } = await Contacts.getContactsAsync({
fields: [Contacts.Fields.Emails],
});
if (data.length > 0) {
const contact = data[0];
console.log(contact);
}

Permission already granted but keep telling not granted REACT-NATIVE

im building a music player and I need to acces to the music files, so the first thing is ask for permissions to acces to the files:
componentDidMount() {
this.requestPermission();
}
requestPermission = async () => {
try {
const userResponse = await PermissionsAndroid.requestMultiple([
PermissionsAndroid.PERMISSIONS.READ_EXTERNAL_STORAGE,
PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE,
]);
if (userResponse === PermissionsAndroid.RESULTS.GRANTED) {
alert("nice");
}else {
alert("no nice");
}
}catch (error) {
alert(error)
}
};
even when I already clicked in allow, and reload the project it wil say no nice, i open the config of the app and the permission to storage is fine, so dont why is this happening
According to documentation requestMultiple will return an object with the permissions as keys and strings as values (see result strings above) indicating whether the user allowed or denied the request or does not want to be asked again.
try this
if (userResponse[PermissionsAndroid.PERMISSIONS.READ_EXTERNAL_STORAGE] === PermissionsAndroid.RESULTS.GRANTED && userResponse[PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE] ===
PermissionsAndroid.RESULTS.GRANTED
) {
alert('nice');
} else {
alert('no nice');
}

react-native-fs cannot access storage

i'm using react-native-fs package to save files to android storage.
when i perform these two lines of code, it works
await RNFS.readDir(RNFS.DocumentDirectoryPath);
=====>/data/user/0/com.youtubedljs/files
await RNFS.readDir(RNFS.CachesDirectoryPath);
=====>/data/user/0/com.youtubedljs/cache
but when i try to access external storage, like Download or documents files
await RNFS.readDir(RNFS.DownloadDirectoryPath);
i get this error
Error: Attempt to get length of null array
i already granted storage permissions to the application, it didn't work.
Update: Works fine on android 8.1, i think that the package doesn't support android 10 yet
Need to give read-write permissions.
that's okay.. but you also need to get incode permissions, before accessing file
import {PermissionsAndroid} from 'react-native';
const granted = await PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE,
);
if (granted === PermissionsAndroid.RESULTS.GRANTED) {
//alert('You can use the location');
console.log('write granted');
return true;
} else {
return false;
}
} catch (err) {
console.warn(err);
return false;
}
First you have to ask for permission
then you can save the into download folder of mobile
import {request, PERMISSIONS} from 'react-native-permissions';
request(
Platform.OS === 'ios'
? PERMISSIONS.IOS.MEDIA_LIBRARY
: PERMISSIONS.ANDROID.WRITE_EXTERNAL_STORAGE,
).then(result => {
console.log(result);
);
});
var path = RNFS.DownloadDirectoryPath + '/filename.txt';

'Attempt to invoke virtual method \'android.content.Context android.app.Application.getApplicationContext()\' on a null object reference'

I'm using https://github.com/AppsFlyerSDK/react-native-appsflyer in our react-native app.
I managed to set up the iOS part of it and ran the integration tests successfully
but I'm struggling with the Android integration.
1st problem:
When I build the app on my device I get this error:
'Attempt to invoke virtual method \'android.content.Context android.app.Application.getApplicationContext()\' on a null object reference'
inside the appsFlyer.initSdk
2nd problem:
When I run the Android SDK Integration test:
I get this result (see screenshot)
Here's my code :
```
...
...
// appsFlyer options
const options = {
devKey: 'Bl9i45ho07lp43',
isDebug: true,
};
if (Platform.OS === 'ios') {
options.appId = '1165972436';
}
this.onInstallConversionDataCanceller = appsFlyer.onInstallConversionData(
(data) => {
console.log(data);
}
);
appsFlyer.initSdk(options,
(result) => {
console.log(result);
},
(error) => {
console.error('error inside appsFlyer.initSdk ==>', error);
}
);
.....
.....
class App extends React.PureComponent {
state = {
appState: AppState.currentState,
}
componentDidMount() {
AppState.addEventListener('change', this._handleAppStateChange);
}
componentWillUnmount() {
if (this.onInstallConversionDataCanceller) {
this.onInstallConversionDataCanceller();
}
AppState.removeEventListener('change', this._handleAppStateChange);
}
_handleAppStateChange = (nextAppState) => {
if (this.state.appState.match(/inactive|background/) && nextAppState === 'active') {
if (Platform.OS === 'ios') {
appsFlyer.trackAppLaunch();
}
}
if (this.state.appState.match(/active|foreground/) && nextAppState === 'background') {
if (this.onInstallConversionDataCanceller) {
this.onInstallConversionDataCanceller();
}
}
this.setState({ appState: nextAppState });
}
}
```
I found the solution:
Initially, I was following the documentation by adding
new RNAppsFlyerPackage(MainApplication.this) inside the getPackages() method in MainApplication.java but I kept having an error saying I couldn't use arguments with RNAppsFlyerPackage()
I had to remove the arguments so that I can build the project, but that didn't make the Android integration tests
1 - The solution was to clean the project
2 - delete the node_modules using :
rm -rf /node_modules
3- after doing that, I was prompted to use arguments inside the method
new RNAppsFlyerPackage(MainApplication.this)
and now the Android integration tests are passing