MediaStore.ACTION_IMAGE_CAPTURE无法获取原图及写入文件求助
解决MediaStore.ACTION_IMAGE_CAPTURE获取原图失败的问题
问题核心原因
你遇到的问题主要源于以下几点:
- 直接传入
MediaStore.Images.Media.EXTERNAL_CONTENT_URI作为EXTRA_OUTPUT,相机应用无权限写入公共媒体目录(Android 10+启用Scoped Storage后限制更严格) - 未给相机Intent授予Uri的临时读写权限
- 存在权限声明冗余/错误,或FileProvider路径配置不当
分步解决方案
1. 修正Manifest配置
清理错误权限,调整FileProvider配置:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.marzinp.mycelium" android:versionCode="120" android:versionName="1.2.0" > <uses-sdk android:minSdkVersion="22" android:targetSdkVersion="30" /> <uses-permission android:name="android.permission.CAMERA" /> <!-- Android 10+写入APP私有目录无需WRITE权限,仅需读取公共媒体时保留READ权限 --> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32"/> <!-- 移除错误的READ_CALENDAR_EXTERNAL_STORAGE权限 --> <uses-feature android:name="android.hardware.camera" android:required="true" /> <application android:allowBackup="true" android:icon="@drawable/lombric" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name="com.marzinp.mycelium.MainActivity" android:configChanges="orientation|screenSize" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <provider android:name="androidx.core.content.FileProvider" <!-- 建议改用androidx版本,兼容更高SDK --> android:authorities="${applicationId}.profileimage.fileprovider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths"></meta-data> </provider> </application> </manifest>
2. 配置FileProvider路径文件
在res/xml目录下创建file_paths.xml,指定相机可访问的APP私有目录:
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <!-- 指向APP外部存储的Pictures目录,相机可写入该目录 --> <external-files-path name="my_images" path="Pictures"/> </paths>
3. 完整相机调用代码
import android.content.Intent; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.net.Uri; import android.os.Bundle; import android.os.Environment; import android.provider.MediaStore; import androidx.appcompat.app.AppCompatActivity; import androidx.core.content.FileProvider; import java.io.File; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; public class MainActivity extends AppCompatActivity { private File mPhotoFile; private static final int REQUEST_CODE_CAMERA = 1; private void photoIntent() { Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); // 确保有相机应用能处理该Intent if (takePictureIntent.resolveActivity(getPackageManager()) == null) { return; } // 创建保存原图的私有目录文件 try { mPhotoFile = createImageFile(); } catch (IOException e) { e.printStackTrace(); return; } // 生成可被相机访问的Content Uri Uri photoUri = FileProvider.getUriForFile( this, "com.marzinp.mycelium.profileimage.fileprovider", // 与Manifest中authorities完全一致 mPhotoFile ); takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri); // 授予相机读写该Uri的临时权限 takePictureIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION); takePictureIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); startActivityForResult(takePictureIntent, REQUEST_CODE_CAMERA); } // 创建唯一命名的图片文件,存储在APP私有外部目录 private File createImageFile() throws IOException { String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date()); String imageFileName = "JPEG_" + timeStamp + "_"; File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES); return File.createTempFile(imageFileName, ".jpg", storageDir); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == REQUEST_CODE_CAMERA && resultCode == RESULT_OK) { // 设置EXTRA_OUTPUT后,Intent不会返回缩略图,直接从文件读取原图 if (mPhotoFile != null && mPhotoFile.exists()) { Bitmap originalBitmap = BitmapFactory.decodeFile(mPhotoFile.getAbsolutePath()); createDrawingView(originalBitmap); } } } // 你的自定义方法 private void createDrawingView(Bitmap bitmap) { // 处理图片逻辑 } }
关键注意事项
- 无需改用CameraX:上述方案完全基于原生
ACTION_IMAGE_CAPTURE,适配你的minSdk22到targetSdk30,新手容易上手 - 不要尝试写入公共媒体目录:Android 10+的Scoped Storage限制了第三方应用对公共目录的直接写入,使用APP私有目录是最简单的解决方案
- 确保FileProvider的
authorities在Manifest和代码中完全一致,否则会出现权限错误
内容的提问来源于stack exchange,提问作者Pierre Marzin
相关产品推荐
相关产品推荐

