iOS asks the user before an app touches the camera, photos, location, microphone, contacts or Bluetooth, and the dialog shows a sentence you supply in Info.plist under a ...UsageDescription key. If the key is missing, iOS terminates the app the moment it requests access, and App Store 10 review rejects vague strings such as "Camera needed", so say what the feature does. In an Expo 6,418 project you never edit Info.plist; you add the keys to app.json, and prebuild writes them:
"ios": {
"supportsTablet": true,
"infoPlist": {
"NSCameraUsageDescription": "BookNest scans book covers and barcodes with the camera.",
"NSPhotoLibraryUsageDescription": "BookNest lets you pick a photo of a book you own."
}
},You can see the Info.plist that prebuild would generate without a Mac, because expo config evaluates every config plugin on any OS:
npx expo config --type introspect --json | jq '.ios.infoPlist
| with_entries(select(.key | endswith("UsageDescription")))'{
"NSCameraUsageDescription": "BookNest scans book covers and barcodes with the camera.",
"NSPhotoLibraryUsageDescription": "BookNest lets you pick a photo of a book you own."
}Most Expo libraries also take the strings as config plugin options, for example ["expo-camera", { "cameraPermission": "..." }], and write a default when you give none, so check the generated list before you submit. iOS shows each dialog only once (Android allows two tries, PermissionsAndroid): a user who taps Don't Allow can change the answer only in the Settings app, which Linking.openSettings() opens at your app's page.