Android API31+相机按钮无响应及拍照后无法跳转至编辑页问题
Android API 31+ 相机拍照后无法跳转至EditorActivity问题排查与解决
问题现象
- API 31+设备上,初始代码点击相机按钮无响应;移除
tempFile.createNewFile();后相机可打开,但拍照后无法跳转至EditorActivity,仅返回主菜单 - 将临时文件路径改为DCIM目录后,Android Studio调试时功能正常,但导出APK安装后,拍照仍无法跳转至EditorActivity
- 已按谷歌文档配置相机权限且权限已授予,文件路径匹配无误
原核心代码
相机点击事件(初始版本)
public void cameraClicked(View view) { Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); File tempFile = new File(Environment.getExternalStorageDirectory().getPath()+ "/photoTemp.png"); try { tempFile.createNewFile(); Uri uri = FileProvider.getUriForFile( this, this.getApplicationContext() .getPackageName() + ".provider", tempFile); takePictureIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, uri); startActivityForResult(takePictureIntent, 2); } catch (IOException e) { e.printStackTrace(); } }
相机点击事件(修改DCIM路径版本)
public void cameraClicked(View view) { Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); File tempFile = new File(Environment.getExternalStorageDirectory() + "/" + Environment.DIRECTORY_DCIM + "/photoTemp.png"); try { tempFile.createNewFile(); Uri uri = FileProvider.getUriForFile( this, this.getApplicationContext() .getPackageName() + ".provider", tempFile); takePictureIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, uri); startActivityForResult(takePictureIntent, 2); } catch (IOException e) { e.printStackTrace(); } }
结果处理方法
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { switch (requestCode) { case 100: if (resultCode == RESULT_OK) { try { Uri uri = data.getData(); InputStream imageStream = getContentResolver().openInputStream(uri); bitmap = BitmapFactory.decodeStream(imageStream); Intent intent = new Intent(this, EditorActivity.class); intent.putExtra("mode", false); startActivity(intent); } catch (Exception ex) { int i = 0; int j = i; } } break; case 2: if(resultCode == RESULT_OK){ bitmap = BitmapFactory.decodeFile(Environment.getExternalStorageDirectory()+ "/" + Environment.DIRECTORY_DCIM + "/photoTemp.png"); Intent intent = new Intent(this, EditorActivity.class); intent.putExtra("mode", true); intent.putExtra("url", Environment.getExternalStorageDirectory() + "/" + Environment.DIRECTORY_DCIM + "/photoTemp.png"); startActivity(intent); } break; case 10001: if (!mHelper.handleActivityResult(requestCode, resultCode, data)) { super.onActivityResult(requestCode, resultCode, data); } break; } }
EditorActivity相关方法
public Uri getImageUri(Context inContext, Bitmap inImage) { ByteArrayOutputStream bytes = new ByteArrayOutputStream(); inImage.compress(Bitmap.CompressFormat.JPEG, 100, bytes); String path = MediaStore.Images.Media.insertImage(inContext.getContentResolver(), inImage, "photoTemp.png", null); return Uri.parse(path); }
解决方案
1. 适配API 31+存储规则,改用应用私有目录
API 31+对外部公共目录的访问限制更严格,直接操作DCIM自定义文件易触发权限问题,建议改用应用私有外部存储目录存储临时文件,无需额外权限:
// 获取应用私有外部存储的DCIM目录 File dcimDir = getExternalFilesDir(Environment.DIRECTORY_DCIM); File tempFile = new File(dcimDir, "photoTemp.png");
同时移除tempFile.createNewFile();,相机应用会自动创建文件,提前创建可能导致权限冲突。
确保FileProvider配置包含该路径,在res/xml/file_paths.xml中添加:
<external-files-path name="my_dcim" path="DCIM/" />
2. 完善权限授予逻辑
仅添加FLAG_GRANT_READ_URI_PERMISSION不足以让相机应用写入文件,需同时添加写入权限:
takePictureIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
或者通过grantUriPermission明确授予所有匹配相机应用权限:
List<ResolveInfo> resInfoList = getPackageManager().queryIntentActivities(takePictureIntent, PackageManager.MATCH_DEFAULT_ONLY); for (ResolveInfo resolveInfo : resInfoList) { String packageName = resolveInfo.activityInfo.packageName; grantUriPermission(packageName, uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION); }
3. 优化onActivityResult逻辑,避免路径依赖
将相机点击事件中的uri保存为Activity成员变量,在onActivityResult中通过ContentResolver访问文件,避免直接依赖绝对路径:
// 成员变量保存uri private Uri cameraImageUri; // 相机点击事件中赋值 cameraImageUri = FileProvider.getUriForFile(...); // onActivityResult中修改 case 2: if(resultCode == RESULT_OK){ try { InputStream is = getContentResolver().openInputStream(cameraImageUri); bitmap = BitmapFactory.decodeStream(is); Intent intent = new Intent(this, EditorActivity.class); intent.putExtra("mode", true); intent.putExtra("image_uri", cameraImageUri.toString()); startActivity(intent); } catch (IOException e) { e.printStackTrace(); } } break;
4. 替换EditorActivity中废弃的API
MediaStore.Images.Media.insertImage在高版本已废弃,改用MediaStore标准插入API:
public Uri getImageUri(Context inContext, Bitmap inImage) { ContentValues values = new ContentValues(); values.put(MediaStore.Images.Media.DISPLAY_NAME, "photoTemp.png"); values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg"); values.put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_DCIM); Uri uri = inContext.getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values); if (uri != null) { try (OutputStream os = inContext.getContentResolver().openOutputStream(uri)) { inImage.compress(Bitmap.CompressFormat.JPEG, 100, os); } catch (IOException e) { e.printStackTrace(); inContext.getContentResolver().delete(uri, null, null); uri = null; } } return uri; }
5. 检查APK签名与权限配置
- 确保导出APK的签名配置与调试一致,避免签名差异导致权限异常
- 在
AndroidManifest.xml中确认权限配置:
<uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" android:minSdkVersion="33" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="32" />
内容的提问来源于stack exchange,提问作者JustMeShortie
相关产品推荐
相关产品推荐

