# βπΌ React Native Permissions
[![npm version](https://badge.fury.io/js/react-native-permissions.svg)](https://badge.fury.io/js/react-native-permissions)
[![npm](https://img.shields.io/npm/dt/react-native-permissions.svg)](https://www.npmjs.org/package/react-native-permissions)
![Platform - Android and iOS](https://img.shields.io/badge/platform-Android%20%7C%20iOS-yellow.svg)
![MIT](https://img.shields.io/dub/l/vibe-d.svg)
[![styled with prettier](https://img.shields.io/badge/styled_with-prettier-ff69b4.svg)](https://github.com/prettier/prettier)
An unified permissions API for React Native on iOS and Android.
## Support
| version | react-native version |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------- |
| 2.0.0+ | 0.60.0+ |
| 2.0.0+ & [`jetify -r`](https://github.com/mikehardy/jetifier/blob/master/README.md#to-reverse-jetify--convert-node_modules-dependencies-to-support-libraries) | 0.59.0 - 0.59.10 |
## Setup
```bash
$ npm install --save react-native-permissions
# --- or ---
$ yarn add react-native-permissions
```
### iOS
By default no permission handler is installed. Update your `Podfile` by choosing the ones you want to check or request, then run `pod install`.
```ruby
# if you have prebuild dynamic cocoapods dependencies and could not migrate
# to use_modular_headers you should use workaround for linking app with dynamic frameworks
# and with static libraries by placing this code at the top of Podfile
#
# Add this code at the top of Podfile right after platform definition
use_frameworks!
dynamic_frameworks = ['RxCocoa', 'RxSwift', 'WhatEverSDKName']
# make all the other dependencies into static libraries by overriding the static_library
pre_install do |installer|
installer.pod_targets.each do |pod|
if !dynamic_frameworks.include?(pod.name)
puts "Overriding the static_library for #{pod.name}"
def pod.build_type;
Pod::Target::BuildType.static_library
# for static framework -
# Pod::Target::BuildType.static_framework
end
end
end
end
```
```ruby
# π¨ If you use use_framework! π¨
# - Ensure that you have installed at least Cocoapods 1.5.0
# - Replace use_framework! with use_modular_headers!
# (see http://blog.cocoapods.org/CocoaPods-1.5.0 for more details)
target 'YourAwesomeProject' do
# β¦
permissions_path = '../node_modules/react-native-permissions/ios'
pod 'Permission-BluetoothPeripheral', :path => "#{permissions_path}/BluetoothPeripheral.podspec"
pod 'Permission-Calendars', :path => "#{permissions_path}/Calendars.podspec"
pod 'Permission-Camera', :path => "#{permissions_path}/Camera.podspec"
pod 'Permission-Contacts', :path => "#{permissions_path}/Contacts.podspec"
pod 'Permission-FaceID', :path => "#{permissions_path}/FaceID.podspec"
pod 'Permission-LocationAlways', :path => "#{permissions_path}/LocationAlways.podspec"
pod 'Permission-LocationWhenInUse', :path => "#{permissions_path}/LocationWhenInUse.podspec"
pod 'Permission-MediaLibrary', :path => "#{permissions_path}/MediaLibrary.podspec"
pod 'Permission-Microphone', :path => "#{permissions_path}/Microphone.podspec"
pod 'Permission-Motion', :path => "#{permissions_path}/Motion.podspec"
pod 'Permission-Notifications', :path => "#{permissions_path}/Notifications.podspec"
pod 'Permission-PhotoLibrary', :path => "#{permissions_path}/PhotoLibrary.podspec"
pod 'Permission-Reminders', :path => "#{permissions_path}/Reminders.podspec"
pod 'Permission-Siri', :path => "#{permissions_path}/Siri.podspec"
pod 'Permission-SpeechRecognition', :path => "#{permissions_path}/SpeechRecognition.podspec"
pod 'Permission-StoreKit', :path => "#{permissions_path}/StoreKit.podspec"
end
```
_β οΈ If you encounter the error `Invalid RNPermission X. Should be one of: ()`, first check that you link at least one permission handler. If you did, try to cleanup Xcode junk data with `npx react-native-clean-project --remove-iOS-build --remove-iOS-pods`_
Then update your `Info.plist` with wanted permissions usage descriptions:
```xml
NSAppleMusicUsageDescription
YOUR TEXT
NSBluetoothAlwaysUsageDescription
YOUR TEXT
NSBluetoothPeripheralUsageDescription
YOUR TEXT
NSCalendarsUsageDescription
YOUR TEXT
NSCameraUsageDescription
YOUR TEXT
NSContactsUsageDescription
YOUR TEXT
NSFaceIDUsageDescription
YOUR TEXT
NSLocationAlwaysAndWhenInUseUsageDescription
YOUR TEXT
NSLocationAlwaysUsageDescription
YOUR TEXT
NSLocationWhenInUseUsageDescription
YOUR TEXT
NSMicrophoneUsageDescription
YOUR TEXT
NSMotionUsageDescription
YOUR TEXT
NSPhotoLibraryUsageDescription
YOUR TEXT
NSRemindersUsageDescription
YOUR TEXT
NSSpeechRecognitionUsageDescription
YOUR TEXT
NSSiriUsageDescription
YOUR TEXT
```
### Android
Add all wanted permissions to your app `android/app/src/main/AndroidManifest.xml` file:
```xml
```
## π Manual linking
Because this package targets React Native 0.60.0+, you will probably don't need to link it manually. Otherwise if it's not the case, follow this additional instructions:
π See manual linking instructions
### iOS
Add this line to your `ios/Podfile` file, then run `pod install`.
```bash
target 'YourAwesomeProject' do
# β¦
pod 'RNPermissions', :path => '../node_modules/react-native-permissions'
end
```
### Android
1. Add the following lines to `android/settings.gradle`:
```gradle
include ':react-native-permissions'
project(':react-native-permissions').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-permissions/android')
```
2. Add the implementation line to the dependencies in `android/app/build.gradle`:
```gradle
dependencies {
// ...
implementation project(':react-native-permissions')
}
```
3. Add the import and link the package in `MainApplication.java`:
```java
import com.reactnativecommunity.rnpermissions.RNPermissionsPackage; // <- add the RNPermissionsPackage import
public class MainApplication extends Application implements ReactApplication {
// β¦
@Override
protected List getPackages() {
@SuppressWarnings("UnnecessaryLocalVariable")
List packages = new PackageList(this).getPackages();
// β¦
packages.add(new RNPermissionsPackage());
return packages;
}
// β¦
}
```
## Understanding permission flow
As permissions are not handled in the same way on iOS and Android, this library provides an abstraction over the two platforms behaviors. To understand it a little better, take a look to these two flowcharts:
### iOS flow
```
βββββββββββββββββββββββββββββββββ
β check(PERMISSIONS.IOS.CAMERA) β
βββββββββββββββββββββββββββββββββ
β
Is the feature available
on this deviceΒ ?
β ββββββ
βββββββββββββ NO ββββββββββββββββ
β ββββββ β
βββββββ βΌ
β YES β βββββββββββββββββββββββ
βββββββ β RESULTS.UNAVAILABLE β
β βββββββββββββββββββββββ
Is the permission
requestableΒ ?
β ββββββ
βββββββββββββ NO ββββββββββββββββ
β ββββββ β
βββββββ βΌ
β YES β βββββββββββββββββββββ
βββββββ β RESULTS.BLOCKED / β
β β RESULTS.GRANTED β
βΌ βββββββββββββββββββββ
ββββββββββββββββββ
β RESULTS.DENIED β
ββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββ
β request(PERMISSIONS.IOS.CAMERA) β
βββββββββββββββββββββββββββββββββββ
β
Does the user accept
the requestΒ ?
β ββββββ
βββββββββββββ NO ββββββββββββββββ
β ββββββ β
βββββββ βΌ
β YES β βββββββββββββββββββ
βββββββ β RESULTS.BLOCKED β
β βββββββββββββββββββ
βΌ
βββββββββββββββββββ
β RESULTS.GRANTED β
βββββββββββββββββββ
```
### Android flow
```
βββββββββββββββββββββββββββββββββββββ
β check(PERMISSIONS.ANDROID.CAMERA) β
βββββββββββββββββββββββββββββββββββββ
β
Is the feature available
on this deviceΒ ?
β ββββββ
βββββββββββββ NO ββββββββββββββββ
β ββββββ β
βββββββ βΌ
β YES β βββββββββββββββββββββββ
βββββββ β RESULTS.UNAVAILABLE β
β βββββββββββββββββββββββ
Is the permission
requestableΒ ?
β ββββββ
βββββββββββββ NO ββββββββββββββββ
β ββββββ β
βββββββ βΌ
β YES β βββββββββββββββββββββ
βββββββ β RESULTS.BLOCKED / β
β β RESULTS.GRANTED β
βΌ βββββββββββββββββββββ
ββββββββββββββββββ
β RESULTS.DENIED βββββββββββββββββββββββββ
ββββββββββββββββββ β
β β
βΌ β
βββββββββββββββββββββββββββββββββββββββ ββββββ
β request(PERMISSIONS.ANDROID.CAMERA) β β NO β
βββββββββββββββββββββββββββββββββββββββ ββββββ
β β
Does the user accept β
the requestΒ ? β
β ββββββ Does the user check
βββββββββββββ NO ββββββ"NeverΒ askΒ again"Β ?
β ββββββ β
βββββββ βββββββ
β YES β β YES β
βββββββ βββββββ
β β
βΌ βΌ
βββββββββββββββββββ βββββββββββββββββββ
β RESULTS.GRANTED β β RESULTS.BLOCKED β
βββββββββββββββββββ βββββββββββββββββββ
```
## API
### Supported permissions
```js
import {PERMISSIONS} from 'react-native-permissions';
// Android permissions
PERMISSIONS.ANDROID.ACCEPT_HANDOVER;
PERMISSIONS.ANDROID.ACCESS_BACKGROUND_LOCATION;
PERMISSIONS.ANDROID.ACCESS_COARSE_LOCATION;
PERMISSIONS.ANDROID.ACCESS_FINE_LOCATION;
PERMISSIONS.ANDROID.ACTIVITY_RECOGNITION;
PERMISSIONS.ANDROID.ADD_VOICEMAIL;
PERMISSIONS.ANDROID.ANSWER_PHONE_CALLS;
PERMISSIONS.ANDROID.BODY_SENSORS;
PERMISSIONS.ANDROID.CALL_PHONE;
PERMISSIONS.ANDROID.CAMERA;
PERMISSIONS.ANDROID.GET_ACCOUNTS;
PERMISSIONS.ANDROID.PROCESS_OUTGOING_CALLS;
PERMISSIONS.ANDROID.READ_CALENDAR;
PERMISSIONS.ANDROID.READ_CALL_LOG;
PERMISSIONS.ANDROID.READ_CONTACTS;
PERMISSIONS.ANDROID.READ_EXTERNAL_STORAGE;
PERMISSIONS.ANDROID.READ_PHONE_NUMBERS;
PERMISSIONS.ANDROID.READ_PHONE_STATE;
PERMISSIONS.ANDROID.READ_SMS;
PERMISSIONS.ANDROID.RECEIVE_MMS;
PERMISSIONS.ANDROID.RECEIVE_SMS;
PERMISSIONS.ANDROID.RECEIVE_WAP_PUSH;
PERMISSIONS.ANDROID.RECORD_AUDIO;
PERMISSIONS.ANDROID.SEND_SMS;
PERMISSIONS.ANDROID.USE_SIP;
PERMISSIONS.ANDROID.WRITE_CALENDAR;
PERMISSIONS.ANDROID.WRITE_CALL_LOG;
PERMISSIONS.ANDROID.WRITE_CONTACTS;
PERMISSIONS.ANDROID.WRITE_EXTERNAL_STORAGE;
// iOS permissions
PERMISSIONS.IOS.BLUETOOTH_PERIPHERAL;
PERMISSIONS.IOS.CALENDARS;
PERMISSIONS.IOS.CAMERA;
PERMISSIONS.IOS.CONTACTS;
PERMISSIONS.IOS.FACE_ID;
PERMISSIONS.IOS.LOCATION_ALWAYS;
PERMISSIONS.IOS.LOCATION_WHEN_IN_USE;
PERMISSIONS.IOS.MEDIA_LIBRARY;
PERMISSIONS.IOS.MICROPHONE;
PERMISSIONS.IOS.MOTION;
PERMISSIONS.IOS.PHOTO_LIBRARY;
PERMISSIONS.IOS.REMINDERS;
PERMISSIONS.IOS.SIRI;
PERMISSIONS.IOS.SPEECH_RECOGNITION;
PERMISSIONS.IOS.STOREKIT;
```
### Permissions statuses
Permission checks and requests resolve into one of these statuses:
| Return value | Notes |
| --------------------- | ----------------------------------------------------------------- |
| `RESULTS.UNAVAILABLE` | This feature is not available (on this device / in this context) |
| `RESULTS.DENIED` | The permission has not been requested / is denied but requestable |
| `RESULTS.GRANTED` | The permission is granted |
| `RESULTS.BLOCKED` | The permission is denied and not requestable anymore |
### Methods
```ts
// type used in usage examples
type PermissionStatus = 'unavailable' | 'denied' | 'blocked' | 'granted';
```
#### check
Check one permission status.
```ts
function check(permission: string): Promise;
```
```js
import {check, PERMISSIONS, RESULTS} from 'react-native-permissions';
check(PERMISSIONS.IOS.LOCATION_ALWAYS)
.then(result => {
switch (result) {
case RESULTS.UNAVAILABLE:
console.log(
'This feature is not available (on this device / in this context)',
);
break;
case RESULTS.DENIED:
console.log(
'The permission has not been requested / is denied but requestable',
);
break;
case RESULTS.GRANTED:
console.log('The permission is granted');
break;
case RESULTS.BLOCKED:
console.log('The permission is denied and not requestable anymore');
break;
}
})
.catch(error => {
// β¦
});
```
---
#### request
Request one permission.
```ts
type Rationale = {
title: string;
message: string;
buttonPositive?: string;
buttonNegative?: string;
buttonNeutral?: string;
};
function request(
permission: string,
rationale?: Rationale,
): Promise;
```
```js
import {request, PERMISSIONS} from 'react-native-permissions';
request(PERMISSIONS.IOS.LOCATION_ALWAYS).then(result => {
// β¦
});
```
---
#### checkNotifications
Check notifications permission status and get notifications settings values.
```ts
interface NotificationSettings {
// properties only availables on iOS
// unavailable settings will not be included in the response object
alert?: boolean;
badge?: boolean;
sound?: boolean;
lockScreen?: boolean;
carPlay?: boolean;
notificationCenter?: boolean;
criticalAlert?: boolean;
}
function checkNotifications(): Promise<{
status: PermissionStatus;
settings: NotificationSettings;
}>;
```
```js
import {checkNotifications} from 'react-native-permissions';
checkNotifications().then(({status, settings}) => {
// β¦
});
```
---
#### requestNotifications
Request notifications permission status and get notifications settings values.
```ts
// only used on iOS
type NotificationOption =
| 'alert'
| 'badge'
| 'sound'
| 'criticalAlert'
| 'carPlay'
| 'provisional';
interface NotificationSettings {
// properties only availables on iOS
// unavailable settings will not be included in the response object
alert?: boolean;
badge?: boolean;
sound?: boolean;
lockScreen?: boolean;
carPlay?: boolean;
notificationCenter?: boolean;
criticalAlert?: boolean;
}
function requestNotifications(
options: NotificationOption[],
): Promise<{
status: PermissionStatus;
settings: NotificationSettings;
}>;
```
```js
import {requestNotifications} from 'react-native-permissions';
requestNotifications(['alert', 'sound']).then(({status, settings}) => {
// β¦
});
```
---
#### openSettings
Open application settings.
```ts
function openSettings(): Promise;
```
```js
import {openSettings} from 'react-native-permissions';
openSettings().catch(() => console.warn('cannot open settings'));
```
## Migrating from v1.x.x
If you are currently using the version `1.x.x` and would like to switch to `v2.x.x`, the only thing you really need to know is that it's now required to select the wanted permission **per platform**.
```js
// v1.x.x
import Permissions from 'react-native-permissions';
Permissions.request('location', {type: 'whenInUse'});
// v2.x.x
import {Platform} from 'react-native';
import {PERMISSIONS, request} from 'react-native-permissions';
request(
Platform.select({
android: PERMISSIONS.ANDROID.ACCESS_FINE_LOCATION,
ios: PERMISSIONS.IOS.LOCATION_WHEN_IN_USE,
}),
);
```
## Additional recipes
#### Check multiples permissions
```js
import {check, PERMISSIONS} from 'react-native-permissions';
// can be done in parallel
Promise.all([
check(PERMISSIONS.IOS.CAMERA),
check(PERMISSIONS.IOS.CONTACTS),
// β¦
]).then(([cameraStatus, contactsStatus /* β¦ */]) => {
console.log({cameraStatus, contactsStatus});
});
```
#### Request multiples permissions
_β οΈΒ Β It's a very bad UX pattern, avoid doing it!_
```js
import {request, PERMISSIONS} from 'react-native-permissions';
// should be done in sequence
async function requestAll() {
const cameraStatus = await request(PERMISSIONS.IOS.CAMERA);
const contactsStatus = await request(PERMISSIONS.IOS.CONTACTS);
return {cameraStatus, contactsStatus};
}
requestAll().then(statuses => console.log(statuses));
```