When you are creating an app that requires access to potentially sensitive information on a user's device, such as their location or contacts, you need to ask for the user's permission first. The expo-permissions module makes requesting these permissions easy, fast, and reliable.
Please read the permissions on iOS and permissions on Android sections carefully before deploying your app to the stores. If you don't configure or explain the permissions properly it may result in your app getting rejected or pulled from the stores. Read more about deploying to the stores in the App Store Deployment Guide.
To request permissions on iOS, you have to describe why the permissions are requested and install the library that can request this permission. In the managed workflow, you can do that by customizing the ios.infoPlist property in your app.json file. When using the bare workflow, you have to edit the info.plist file directly.
See the Permission types below to learn about what infoPlist property you need for each permission. You can find the full list of available properties in Apple's InfoPlistKeyReference. Apple also documents the basic guidelines for the structure of the message in the Human Interface Guidelines.
Note: apps using permissions without descriptions may be rejected from the App Store. (see the App Store Deployment Guide)
On Android, permissions are little bit simpler than iOS. In the managed workflow, permissions are controlled via the android.permissions property in your app.json file. In the bare workflow, they have to be defined in your AndroidManifest.xml.
Some Expo and React Native modules include permissions by default. If you use expo-location, for example, both the ACCESS_COARSE_LOCATION and ACCESS_FINE_LOCATION are implied and added to your app's permissions automatically.
To limit the permissions your managed workflow app requires, set the android.permissions property in your app.json file to list only the permissions you need, and Expo will also include the minimum permissions it requires to run. If you leave this property out, all permissions will be included in your app. When using the bare workflow, you have to blacklist permissions in your AndroidManifest.xml manually.
Note: apps using dangerous or signature permissions without valid reasons may be rejected by Google. Make sure you follow the Android permissions best practices when submitting your app.
Note: by default, the permissions implied by the modules you installed are added to the AndroidManifest.xml. To exclude permissions, you have to define the android.permissions manifest property or blacklist them in the bare workflow.
On web permissions like the Camera and Location can only be requested from a secure context, e.g. using https:// or http://localhost. This limitation is similar to Android's manifest permissions and iOS's infoPlist usage messages and enforced to increase privacy.
Often you want to be able to test what happens when a user rejects a permission, to ensure that it has the desired behavior. An operating-system level restriction on both iOS and Android prohibits an app from asking for the same permission more than once (you can imagine how this could be annoying for the user to be repeatedly prompted for permissions). So in order to test different flows involving permissions in development, you may need to uninstall and reinstall the Expo client app. In the simulator this is as easy as deleting the app, and expo-cli will automatically install it again next time you launch the project.
expo-permissions includes the shared infrastructure for handling system permissions. On iOS, it does not include the code specific to particular permissions. For example, if you want to use the MEDIA_LIBRARY permission, you need to install expo-image-picker or expo-media-library.
The following table shows you which permissions correspond to which packages.
When adding Expo and other React Native modules to your project, certain Android permissions might be implied automatically. The modules should only add relevant permissions required to use the module, however, sometimes you may want to remove some of these permissions.
Since the android.permissions manifest property doesn't work in the bare workflow- when you want to exclude specific permissions from the build, you have to "blacklist" them in your AndroidManifest.xml. You can do that with the tools:node="remove" attribute on the <use-permission> tag.
Get or ask permission for protected functionality within the app. This returns the result for the requested permissions. It also returns additional callback to interact based on user input.
permissionTypes (Type|Type[]) -- One or more types to get or ask permission for. After the permission status is fetched, you can show different UI based on the current status.
permissionOptions -- Optional configuration to change the behavior of the hook.
get (boolean) -- Retrieves the permission status without interacting with the user, true by default.
ask (boolean) -- Prompts the user with the requested permission directly. Without using the askPermission callback, false by default.
permission (PermissionsResponse|undefined) -- An object with information about the permissions, including status, expiration, and scope (if applicable).
askPermission (() => void) -- A callback to ask the user for permission.
getPermission (() => void) -- A callback to get the permission status without interacting with the user.
asyncfunctionalertIfRemoteNotificationsDisabledAsync(){const{ status }=awaitPermissions.getAsync(Permissions.NOTIFICATIONS);if(status !=='granted'){alert('Hey! You might want to enable notifications for my app, they are good.');}}asyncfunctioncheckMultiPermissions(){const{ status, expires, permissions }=awaitPermissions.getAsync(Permissions.CALENDAR,Permissions.CONTACTS);if(status !=='granted'){alert('Hey! You have not enabled selected permissions');}}
asyncfunctiongetLocationAsync(){// permissions returns only for location permissions on iOS and under certain conditions, see Permissions.LOCATIONconst{ status, permissions }=awaitPermissions.askAsync(Permissions.LOCATION);if(status ==='granted'){returnLocation.getCurrentPositionAsync({ enableHighAccuracy:true});}else{thrownewError('Location permission not granted');}}
The permission response is an object describing the current state of the requested permission(s). This response contains the top-level status, granted, expires and canAskAgain properties representing the outcome for all individual permissions.
interfacePermissionResponse{
status:'granted'|'undetermined'|'denied';
granted:boolean;
expires:'never'|number;
canAskAgain:boolean;
permissions:{// an object with an entry for each permission requested[permissionType:string/* PermissionType */]:PermissionInfo;};}
This property coincides with the expiration time of the permission that expires the earliest. When none of the requested permissions expires, it's set to never.
This object contains information about a single requested permission, it's retuned within the PermissionResponse using the permissions property. It also may include additional platform-specific info, like the scope of the permission.
The permission type for user-facing notifications and remote push notifications.
Android: it doesn't require any permissions in your manifest.
iOS: it requires the expo-notifications module and doesn't require a message.
Note (iOS): Asking for this permission asks the user not only for permission to register for push/remote notifications, but also for showing notifications as such. At the moment remote notifications will only be received when notifications are permitted to play a sound, change the app badge or be displayed as an alert. As iOS is more detailed when it comes to notifications permissions, this permission status will contain not only status and expires, but also Boolean values for allowsSound, allowsAlert and allowsBadge.
Note (iOS): This does not disambiguate undetermined from denied and so will only ever return granted or undetermined. This is due to the way the underlying native API is implemented. On iOS simulators, since they don't support registering for push notifications, you will always get undetermined result.
Note (Android): Android does not differentiate between permissions for local and remote notifications, so status of permission for NOTIFICATIONS should always be the same as the status for USER_FACING_NOTIFICATIONS.
The permission type for user-facing notifications. This does not register your app to receive remote push notifications; see the NOTIFICATIONS permission.
Android:this permission is the same as NOTIFICATIONS and returns the status from that permission.
iOS: it requires the expo-notifications module and doesn't require a message.
Note (iOS): It provides more detailed permissions, so the permission status will contain not only status and expires, but also Boolean values for allowsSound, allowsAlert and allowsBadge.
iOS: it requires the expo-location module and one of the messages below.
Note (iOS): This is not working with this permission being not individually, Permissions.askAsync(Permissions.SOME_PERMISSIONS, Permissions.LOCATION, Permissions.CAMERA, ...) would throw.
On iOS ask for this permission type individually.
Note (iOS): In Expo client on iOS this permission will always ask the user for permission to access location data while the app is in use.
If you would like to access location data in a standalone app, note that you'll need to provide location usage descriptions in app.json. For more information see Deploying to App Stores guide.
Returns whether permission is granted only for location updates when app is in use (whenInUse), even when app is backgrounded (always) or when permission is not granted (none).
On devices running Android in versions lower than 10, scope value is either always or none depending on permission being granted. There is no special background location permission on Android 9 and below.
Due to the design of the location permission API on iOS we aren't able to provide you with methods for asking for whenInUse or always location usage permission specifically. However, you can customize the behavior by providing the following sets of usage descriptions:
if you provide only NSLocationWhenInUseUsageDescription, your application will only ever ask for location access permission "when in use",
if you provide both NSLocationWhenInUseUsageDescription and NSLocationAlwaysAndWhenInUseUsageDescription, your application will only ask for "when in use" permission on iOS 10, whereas on iOS 11+ it will show a dialog to the user where he'll be able to pick whether he'd like to give your app permission to access location always or only when the app is in use,
if you provide all three: NSLocationWhenInUseUsageDescription, NSLocationAlwaysAndWhenInUseUsageDescription and NSLocationAlwaysUsageDescription, your application on iOS 11+ will still show a dialog described above and on iOS 10 it will only ask for "always" location permission.
Note (iOS): You can request this permission with the expo-barcode-scanner, expo-camera, expo-face-detector, expo-image-picker, or expo-media-library module.
The permission for accessing DeviceMotion and DeviceOrientation in the web browser. This can only be requested from a website using HTTPS (expo web --https). This permission cannot be silently retrieved, you can only request it. This permission can only be requested with a user interaction i.e. a button press.