๐ Permission Purpose Strings
What it is
Human-readable explanations in Info.plist shown in the system permission dialog: NSCameraUsageDescription, NSPhotoLibraryUsageDescription, NSLocationWhenInUseUsageDescription, NSMicrophoneUsageDescription, NSContactsUsageDescription, and friends. If your binary links an API that can touch a protected resource (even via a third-party SDK), the matching key must exist.
When you need it
Whenever your app โ or any SDK you embed โ references a protected API. Classic surprise: an image-picker or analytics SDK references the camera, so you need NSCameraUsageDescription even if you never open the camera yourself. Missing keys cause ITMS-90683 and the upload is rejected during processing (you get a silent email, the build never appears in TestFlight).
Setup
All stacks
Write specific, honest strings:
- โ "We use the camera to scan receipts so you don't have to type them."
- โ "Camera needed" / "This app requires camera access" (vague strings are rejected under 5.1.1).
Audit which keys you need: search your Info.plist after a release build, and check each SDK's docs for required usage descriptions.
Native (Xcode)
Xcode: target โ Info tab โ add keys (e.g. Privacy - Camera Usage Description). They live in Info.plist as NSCameraUsageDescription etc.
Expo
Set them in app.json under expo.ios.infoPlist:
"ios": { "infoPlist": { "NSCameraUsageDescription": "We use the camera to scan receipts." } }
Many config plugins (expo-camera, expo-image-picker, expo-location) accept the string as a plugin option and inject it for you.
React Native (bare)
Edit ios/<AppName>/Info.plist directly and add the NS...UsageDescription keys. Libraries like react-native-vision-camera and react-native-image-picker list exactly which keys they require.
Flutter
Edit ios/Runner/Info.plist. The permission_handler package's README maps each permission to its required Info.plist key (and you may need to enable macros in the Podfile post-install hook).
App Review rules
- Upload-time: missing keys โ automatic
ITMS-90683rejection email; the build silently never appears. - Review-time (5.1.1): vague or boilerplate strings get rejected; the string must explain a real user-facing benefit.
- Request permissions in context (when the user taps the camera button), not all at launch.
Privacy label impact
Each granted permission usually implies a privacy-label category: location โ Location, contacts โ Contacts, camera/photos โ Photos or Videos if you upload them. Asking permission but declaring nothing โ or vice versa โ is a mismatch reviewers catch.