Android 13/12调用相机拍照时OnActivityResult返回Result.Canceled求助
问题分析与解决方案
你的问题核心是Android 12/13的Scoped Storage限制,以及直接使用Uri.FromFile生成的file://Uri无法被相机应用跨进程访问,导致相机返回取消状态。同时,当指定MediaStore.ExtraOutput时,相机不会在返回的Intent中携带data,这是正常行为,需要直接使用预先指定的文件路径。
解决方案步骤
1. 改用FileProvider生成可跨进程访问的Content Uri
Android 7.0+禁止跨应用直接访问file://Uri,必须使用FileProvider生成content://格式的Uri,授予相机应用临时访问权限。
步骤1.1 在AndroidManifest中注册FileProvider
在<application>标签内添加以下配置:
<provider android:name="androidx.core.content.FileProvider" android:authorities="${applicationId}.fileprovider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> </provider>
步骤1.2 创建文件路径配置文件
在Resources/xml目录下新建file_paths.xml(没有xml目录则手动创建):
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <!-- 映射应用外部私有存储下的Inventory目录 --> <external-files-path name="inventory_images" path="Inventory" /> </paths>
2. 修改拍照触发代码
替换Uri.FromFile为FileProvider.GetUriForFile,并调整Intent的Flag和文件路径:
TakePicture.Click += delegate { if (slabDetails != null) { // 使用应用外部私有存储目录,避免Scoped Storage限制 var inventoryDir = new File(ApplicationContext.GetExternalFilesDir(null), "Inventory"); if (!inventoryDir.Exists()) { inventoryDir.Mkdirs(); // 创建目录(如果不存在) } File SlabFile = new File(inventoryDir, slabDetails.ExtSlabNo + ".jpg"); // 用FileProvider生成Content Uri imageUri = FileProvider.GetUriForFile(this, PackageName + ".fileprovider", SlabFile); Intent camIntent = new Intent(MediaStore.ActionImageCapture); // 移除不必要的ClearTop/SingleTop Flag camIntent.PutExtra(MediaStore.ExtraOutput, imageUri); // 授予相机临时读写权限 camIntent.AddFlags(ActivityFlags.GrantReadUriPermission | ActivityFlags.GrantWriteUriPermission); // 检查相机应用是否可用 if (camIntent.ResolveActivity(PackageManager) != null) { StartActivityForResult(camIntent, 2); } } };
3. 调整OnActivityResult处理逻辑
当指定MediaStore.ExtraOutput时,相机返回的data必然为null,需要直接使用预先保存的imageUri或文件路径:
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data) { base.OnActivityResult(requestCode, resultCode, data); switch (requestCode) { case 2:// 相机返回 if (resultCode == Result.Ok) { try { // 直接使用imageUri对应的文件,而非data new SyncDataTask(this, imageUri, 1, db).Execute(); } catch (Exception ex) { var method = System.Reflection.MethodBase.GetCurrentMethod(); var methodName = method.Name; var className = method.ReflectedType.Name; MainActivity.SaveLogReport(className, methodName, ex); } catch (OutOfMemoryError ex) { ex.PrintStackTrace(); } } } }
4. 清理冗余权限
Android 12/13中,WRITE_EXTERNAL_STORAGE和MANAGE_EXTERNAL_STORAGE对于你的场景是冗余的(使用应用私有存储无需这些权限),可以从AndroidManifest中移除:
<!-- 保留必要权限即可 --> <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" /> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.CAMERA" /> <uses-feature android:name="android.hardware.camera" /> <uses-feature android:name="android.hardware.camera.autofocus" />
内容的提问来源于stack exchange,提问作者Sudheer
相关产品推荐
相关产品推荐

