Mathieu Acthernoene 4d93298896 Add warning about Xcode stale data cleanup | 5 years ago | |
---|---|---|
.github | 5 years ago | |
android | 5 years ago | |
example | 5 years ago | |
ios | 5 years ago | |
src | 5 years ago | |
.editorconfig | 5 years ago | |
.eslintignore | 5 years ago | |
.eslintrc.js | 5 years ago | |
.gitignore | 5 years ago | |
.prettierignore | 5 years ago | |
.prettierrc | 5 years ago | |
.yarnrc | 5 years ago | |
CODEOWNERS | 5 years ago | |
LICENSE | 5 years ago | |
README.md | 5 years ago | |
RNPermissions.podspec | 5 years ago | |
package.json | 5 years ago | |
tsconfig.json | 5 years ago | |
yarn.lock | 5 years ago |
An unified permissions API for React Native on iOS and Android.
version | react-native version |
---|---|
2.0.0+ | 0.60.0+ |
2.0.0+ & jetify -r |
0.59.0 - 0.59.10 |
$ npm install --save react-native-permissions
# --- or ---
$ yarn add react-native-permissions
By default no permission handler is installed. Update your Podfile
by choosing the ones you want to check or request, then run pod install
.
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 have the error Invalid RNPermission X. Should be one of: ()
, try to cleanup Xcode stale data with npx react-native-clean-project --remove-iOS-build --remove-iOS-pods && rm -fr ./node_modules
Then update your Info.plist
with wanted permissions usage descriptions:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<!-- ๐จ Keep only the permissions used in your app ๐จ -->
<key>NSAppleMusicUsageDescription</key>
<string>YOUR TEXT</string>
<key>NSBluetoothAlwaysUsageDescription</key>
<string>YOUR TEXT</string>
<key>NSBluetoothPeripheralUsageDescription</key>
<string>YOUR TEXT</string>
<key>NSCalendarsUsageDescription</key>
<string>YOUR TEXT</string>
<key>NSCameraUsageDescription</key>
<string>YOUR TEXT</string>
<key>NSContactsUsageDescription</key>
<string>YOUR TEXT</string>
<key>NSFaceIDUsageDescription</key>
<string>YOUR TEXT</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>YOUR TEXT</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>YOUR TEXT</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>YOUR TEXT</string>
<key>NSMicrophoneUsageDescription</key>
<string>YOUR TEXT</string>
<key>NSMotionUsageDescription</key>
<string>YOUR TEXT</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>YOUR TEXT</string>
<key>NSRemindersUsageDescription</key>
<string>YOUR TEXT</string>
<key>NSSpeechRecognitionUsageDescription</key>
<string>YOUR TEXT</string>
<!-- โฆ -->
</dict>
</plist>
Add all wanted permissions to your app android/app/src/main/res/AndroidManifest.xml
file:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.myawesomeapp">
<!-- ๐จ Keep only the permissions used in your app ๐จ -->
<uses-permission android:name="android.permission.ACCEPT_HANDOVER" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" />
<uses-permission android:name="android.permission.ANSWER_PHONE_CALLS" />
<uses-permission android:name="android.permission.BODY_SENSORS" />
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
<uses-permission android:name="android.permission.READ_CALENDAR" />
<uses-permission android:name="android.permission.READ_CALL_LOG" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_PHONE_NUMBERS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.READ_SMS" />
<uses-permission android:name="android.permission.RECEIVE_MMS" />
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission.RECEIVE_WAP_PUSH" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.SEND_SMS" />
<uses-permission android:name="android.permission.USE_SIP" />
<uses-permission android:name="android.permission.WRITE_CALENDAR" />
<uses-permission android:name="android.permission.WRITE_CALL_LOG" />
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="com.android.voicemail.permission.ADD_VOICEMAIL" />
<!-- โฆ -->
</manifest>
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:
Add this line to your ios/Podfile
file, then run pod install
.
target 'YourAwesomeProject' do
# โฆ
pod 'RNPermissions', :path => '../node_modules/react-native-permissions'
end
android/settings.gradle
:include ':react-native-permissions'
project(':react-native-permissions').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-permissions/android')
android/app/build.gradle
:dependencies {
// ...
implementation project(':react-native-permissions')
}
MainApplication.java
:import com.reactnativecommunity.rnpermissions.RNPermissionsPackage; // <- add the RNPermissionsPackage import
public class MainApplication extends Application implements ReactApplication {
// โฆ
@Override
protected List<ReactPackage> getPackages() {
@SuppressWarnings("UnnecessaryLocalVariable")
List<ReactPackage> packages = new PackageList(this).getPackages();
// โฆ
packages.add(new RNPermissionsPackage());
return packages;
}
// โฆ
}
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:
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 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 โ
โโโโโโโโโโโโโโโโโโโ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 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 โ
โโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโ
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;
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 |
// type used in usage examples
type PermissionStatus = 'unavailable' | 'denied' | 'blocked' | 'granted';
Check one permission status.
function check(permission: string): Promise<PermissionStatus>;
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 one permission.
type Rationale = {
title: string;
message: string;
buttonPositive?: string;
buttonNegative?: string;
buttonNeutral?: string;
};
function request(
permission: string,
rationale?: Rationale,
): Promise<PermissionStatus>;
import {request, PERMISSIONS} from 'react-native-permissions';
request(PERMISSIONS.IOS.LOCATION_ALWAYS).then(result => {
// โฆ
});
Check notifications permission status and get notifications settings values.
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;
}>;
import {checkNotifications} from 'react-native-permissions';
checkNotifications().then(({status, settings}) => {
// โฆ
});
Request notifications permission status and get notifications settings values.
// 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;
}>;
import {requestNotifications} from 'react-native-permissions';
requestNotifications(['alert', 'sound']).then(({status, settings}) => {
// โฆ
});
Open application settings.
function openSettings(): Promise<void>;
import {openSettings} from 'react-native-permissions';
openSettings().catch(() => console.warn('cannot open settings'));
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});
});
โ ๏ธย ย Itโs a very bad UX pattern, avoid doing it!
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};
}
console.log(requestAll());