|
|
5 years ago | |
|---|---|---|
| .github | 5 years ago | |
| android | 6 years ago | |
| example | 5 years ago | |
| ios | 5 years ago | |
| src | 6 years ago | |
| .editorconfig | 6 years ago | |
| .eslintignore | 6 years ago | |
| .eslintrc.js | 6 years ago | |
| .gitignore | 6 years ago | |
| .prettierignore | 6 years ago | |
| .prettierrc | 6 years ago | |
| .yarnrc | 6 years ago | |
| CODEOWNERS | 6 years ago | |
| LICENSE | 6 years ago | |
| README.md | 5 years ago | |
| RNPermissions.podspec | 6 years ago | |
| mock.js | 6 years ago | |
| package.json | 5 years ago | |
| tsconfig.json | 6 years ago | |
| yarn.lock | 6 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
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>
<key>NSSiriUsageDescription</key>
<string>YOUR TEXT</string>
<!-- โฆ -->
</dict>
</plist>
Invalid RNPermission X. Should be one of: ()npx react-native-clean-project --remove-iOS-build --remove-iOS-podsuse_frameworks!, replace it by use_modular_headers! - see this blog post for more details. Create empty Swift file in XCode. Then add โ:modular_headers => falseโ to Pods with build errors:pod 'glog', :podspec => '../node_modules/react-native/third-party-podspecs/glog.podspec', :modular_headers => false
pod 'Folly', :podspec => '../node_modules/react-native/third-party-podspecs/Folly.podspec', :modular_headers => false
use_frameworks! but canโt replace it with use_modular_headers!, check the following workaround:# Add this code at the top of Podfile right after platform definition.
# It will make all the dynamic frameworks turning into static libraries.
use_frameworks!
$dynamic_frameworks = ['RxCocoa', 'RxSwift', 'WhatEverSDKName']
pre_install do |installer|
installer.pod_targets.each do |pod|
if !$dynamic_frameworks.include?(pod.name)
puts "Overriding the static_framework? method for #{pod.name}"
def pod.build_type;
Pod::Target::BuildType.static_library
end
end
end
end
Add all wanted permissions to your app android/app/src/main/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'));
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.
// 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,
}),
);
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};
}
requestAll().then(statuses => console.log(statuses));