You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 13:20:59