1import { 2 AndroidConfig, 3 ConfigPlugin, 4 createRunOncePlugin, 5 InfoPlist, 6 withInfoPlist, 7} from '@expo/config-plugins'; 8 9const pkg = require('expo-image-picker/package.json'); 10 11const CAMERA_USAGE = 'Allow $(PRODUCT_NAME) to access your camera'; 12const MICROPHONE_USAGE = 'Allow $(PRODUCT_NAME) to access your microphone'; 13const READ_PHOTOS_USAGE = 'Allow $(PRODUCT_NAME) to access your photos'; 14 15type Props = { 16 photosPermission?: string | false; 17 cameraPermission?: string | false; 18 microphonePermission?: string | false; 19}; 20 21export function setImagePickerInfoPlist( 22 infoPlist: InfoPlist, 23 { cameraPermission, microphonePermission, photosPermission }: Props 24): InfoPlist { 25 if (photosPermission === false) { 26 delete infoPlist.NSPhotoLibraryUsageDescription; 27 } else { 28 infoPlist.NSPhotoLibraryUsageDescription = 29 photosPermission || infoPlist.NSPhotoLibraryUsageDescription || READ_PHOTOS_USAGE; 30 } 31 if (cameraPermission === false) { 32 delete infoPlist.NSCameraUsageDescription; 33 } else { 34 infoPlist.NSCameraUsageDescription = 35 cameraPermission || infoPlist.NSCameraUsageDescription || CAMERA_USAGE; 36 } 37 if (microphonePermission === false) { 38 delete infoPlist.NSMicrophoneUsageDescription; 39 } else { 40 infoPlist.NSMicrophoneUsageDescription = 41 microphonePermission || infoPlist.NSMicrophoneUsageDescription || MICROPHONE_USAGE; 42 } 43 return infoPlist; 44} 45 46export const withAndroidImagePickerPermissions: ConfigPlugin<Props | void> = ( 47 config, 48 { cameraPermission, microphonePermission } = {} 49) => { 50 if (microphonePermission !== false) { 51 config = AndroidConfig.Permissions.withPermissions(config, ['android.permission.RECORD_AUDIO']); 52 } 53 54 // If the user manually sets any of the permissions to `false`, then we should block the permissions to ensure no 55 // package can add them. 56 config = AndroidConfig.Permissions.withBlockedPermissions( 57 config, 58 [ 59 microphonePermission === false && 'android.permission.RECORD_AUDIO', 60 cameraPermission === false && 'android.permission.CAMERA', 61 ].filter(Boolean) as string[] 62 ); 63 64 // NOTE(EvanBacon): It's unclear if we should block the WRITE_EXTERNAL_STORAGE/READ_EXTERNAL_STORAGE permissions since 65 // they're used for many other things besides image picker. 66 67 return config; 68}; 69 70const withImagePicker: ConfigPlugin<Props | void> = ( 71 config, 72 { photosPermission, cameraPermission, microphonePermission } = {} 73) => { 74 config = withInfoPlist(config, (config) => { 75 config.modResults = setImagePickerInfoPlist(config.modResults, { 76 photosPermission, 77 cameraPermission, 78 microphonePermission, 79 }); 80 return config; 81 }); 82 83 if (microphonePermission !== false) { 84 config = AndroidConfig.Permissions.withPermissions(config, ['android.permission.RECORD_AUDIO']); 85 } 86 87 // If the user manually sets any of the permissions to `false`, then we should block the permissions to ensure no 88 // package can add them. 89 config = AndroidConfig.Permissions.withBlockedPermissions( 90 config, 91 [ 92 microphonePermission === false && 'android.permission.RECORD_AUDIO', 93 cameraPermission === false && 'android.permission.CAMERA', 94 ].filter(Boolean) as string[] 95 ); 96 97 // NOTE(EvanBacon): It's unclear if we should block the WRITE_EXTERNAL_STORAGE/READ_EXTERNAL_STORAGE permissions since 98 // they're used for many other things besides image picker. 99 100 return config; 101}; 102 103export default createRunOncePlugin(withImagePicker, pkg.name, pkg.version); 104