如何消除Android端Expo Go拍照弹出的“允许修改此照片”提示
问题背景
开发React Native Expo应用时,使用expo-image-picker实现拍照功能,通过expo-media-library将拍摄的图片保存到自定义目录,功能整体运行正常,但在Android设备上,用户每次拍摄图片后都会弹出*"Allow Expo Go to modify this photo?"*的弹窗,严重影响用户体验。
依赖版本信息
- react-native: 0.64.3
- expo: ~44.0.0
- expo-image-picker: ~12.0.2
- expo-media-library: ~14.0.0
原有功能实现代码
import * as ImagePicker from "expo-image-picker"; import * as MediaLibrary from "expo-media-library"; const savePhoto = async (data, onSucess) => { const asset = await MediaLibrary.createAssetAsync(data?.uri); const album = await MediaLibrary.createAlbumAsync( "TEST_FOLDER", asset, false ); const albumAssets = await MediaLibrary.getAssetsAsync({ album: album, first: 1, sortBy: [[MediaLibrary.SortBy.creationTime, false]], }); if (albumAssets?.assets[0]) { onSucess(albumAssets.assets[0], data); } }; const takePicture = async (onSucess, onError) => { let data = await ImagePicker.launchCameraAsync({ mediaTypes: ImagePicker.MediaTypeOptions.Images, quality: 0.8, allowsEditing: true, base64: true, }); if (data.cancelled === false) { savePhoto(data, onSucess); } else { onError(); } };
原有app.json配置
{ "expo": { "name": "product", "slug": "product_frontend", "version": "1.0.0", "orientation": "landscape", "icon": "./assets/images/icon.png", "userInterfaceStyle": "automatic", "splash": { "image": "./assets/images/splash.png", "resizeMode": "contain", "backgroundColor": "#ffffff" }, "plugins": [ [ "expo-media-library", { "photosPermission": "Allow $(PRODUCT_NAME) to access your photos.", "savePhotosPermission": "Allow $(PRODUCT_NAME) to save photos.", "isAccessMediaLocationEnabled": "true" } ], [ "expo-image-picker", { "cameraPermission": "Allow $(PRODUCT_NAME) to access your camera", "photosPermission": "The app accesses your photos to let you share them with your friends." } ] ], "updates": { "fallbackToCacheTimeout": 0 }, "assetBundlePatterns": ["**/*"], "ios": { "supportsTablet": true }, "android": { "package": "com.comapny.product", "adaptiveIcon": { "foregroundImage": "./assets/images/adaptive-icon.png", "backgroundColor": "#FFFFFF" }, "softwareKeyboardLayoutMode": "pan", "permissions": [] }, "web": { "favicon": "./assets/images/favicon.png" }, "scheme": "product" } }
问题原因
该弹窗由Android 10及以上版本的分区存储(Scoped Storage)机制触发:
- 开启
allowsEditing: true参数后,相机拍摄并编辑后的临时图片存储在系统相机/Expo Go的私有缓存目录,不属于当前应用的自有存储路径。 - 直接调用
MediaLibrary接口将该路径下的文件写入公共媒体目录时,系统会判定应用正在修改非自身所有的媒体文件,每次操作都会弹出临时授权确认弹窗。 - 现有配置中Android节点的
permissions数组为空,未声明完整的媒体访问权限,无法获得媒体目录的长期访问授权。 - 原有代码每次保存时都调用
createAlbumAsync,重复触发目录写入的权限校验,也会增加弹窗触发概率。
解决方案
按以下步骤调整即可消除重复弹窗:
- 按需关闭编辑参数
如果业务不需要用户拍摄后在相机界面裁剪图片,直接将launchCameraAsync中的allowsEditing参数设为false,拍摄后的临时文件路径归属于当前应用,不会触发跨目录修改校验,该操作可解决80%以上的弹窗问题。 - 补全Android权限声明
修改app.json中Android节点的permissions配置,添加必要的媒体访问权限,修改后配置如下:"android": { "package": "com.comapny.product", "adaptiveIcon": { "foregroundImage": "./assets/images/adaptive-icon.png", "backgroundColor": "#FFFFFF" }, "softwareKeyboardLayoutMode": "pan", "permissions": [ "READ_EXTERNAL_STORAGE", "WRITE_EXTERNAL_STORAGE", "ACCESS_MEDIA_LOCATION" ] } - 调整文件保存逻辑
引入expo-file-system依赖,先将相机返回的临时文件复制到应用自有缓存目录,再从自有目录创建媒体资源,避免直接操作其他应用目录下的文件;同时优化相册创建逻辑,相册已存在时直接添加资源,不要重复调用创建接口。修改后的保存逻辑代码如下:import * as ImagePicker from "expo-image-picker"; import * as MediaLibrary from "expo-media-library"; import * as FileSystem from "expo-file-system"; const savePhoto = async (data, onSucess) => { // 生成应用缓存目录下的目标文件路径 const fileExt = data.uri.split('.').pop(); const tempAppPath = `${FileSystem.cacheDirectory}temp_camera_${Date.now()}.${fileExt}`; // 将相机返回的临时文件复制到应用自有目录 await FileSystem.copyAsync({ from: data.uri, to: tempAppPath }); // 从应用自有路径创建媒体资源 const asset = await MediaLibrary.createAssetAsync(tempAppPath); // 检查相册是否存在,不存在再创建 let album = await MediaLibrary.getAlbumAsync("TEST_FOLDER"); if (!album) { album = await MediaLibrary.createAlbumAsync("TEST_FOLDER", asset, false); } else { await MediaLibrary.addAssetsToAlbumAsync([asset], album, false); } const albumAssets = await MediaLibrary.getAssetsAsync({ album: album, first: 1, sortBy: [[MediaLibrary.SortBy.creationTime, false]], }); if (albumAssets?.assets[0]) { onSucess(albumAssets.assets[0], data); } // 清理临时缓存文件 await FileSystem.deleteAsync(tempAppPath, { idempotent: true }); }; // takePicture方法逻辑保持不变即可 const takePicture = async (onSucess, onError) => { let data = await ImagePicker.launchCameraAsync({ mediaTypes: ImagePicker.MediaTypeOptions.Images, quality: 0.8, allowsEditing: true, // 如需保留编辑能力无需修改该参数 base64: true, }); if (data.cancelled === false) { savePhoto(data, onSucess); } else { onError(); } }; - 重新构建应用
配置修改完成后,执行expo prebuild --clean清理旧的原生配置缓存,再重新启动开发环境。注意官方Expo Go客户端存在签名和权限限制,若测试时仍有弹窗,可构建自定义开发客户端(dev client)或正式安装包测试,权限配置即可完全生效。
内容的提问来源于stack exchange,提问作者Tharaka Ananda
相关产品推荐
相关产品推荐

