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

Android最新设备调用默认相机录视频始终返回取消结果问题

Android 10+ 相机录制视频返回RESULT_CANCELED(结果码0)问题修复

问题原因

在Android 10及以上版本,受Scoped Storage和系统相机应用行为变更影响:

  1. 仅通过Intent.FLAG_GRANT_READ_URI_PERMISSION/FLAG_GRANT_WRITE_URI_PERMISSION设置权限,无法保证所有相机应用能正确获取Uri读写权限;
  2. 部分相机应用在接收EXTRA_OUTPUT时,若权限不足会直接返回RESULT_CANCELED,且不会返回Intent数据;
  3. 旧版startActivityForResult的结果处理逻辑依赖返回的Intent数据,但新系统下设置EXTRA_OUTPUT后,相机应用不会将Uri放入返回Intent中。

修复方案

方案1:完善FileProvider权限授予(适配私有目录)

针对你当前使用应用私有目录的实现,修改权限授予逻辑,明确给相机应用授予Uri读写权限:

private void dispatchTakeVideoIntent() {
    Intent takeVideoIntent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
    PackageManager pm = mActivity.getPackageManager();
    ComponentName cameraComponent = takeVideoIntent.resolveActivity(pm);
    
    if (cameraComponent != null) {
        File mediaFile = null;
        try {
            mediaFile = createVideoFile();
        } catch (IOException ex) {
            ex.printStackTrace();
            return;
        }
        
        if (mediaFile != null) {
            Uri uriFile = FileProvider.getUriForFile(mActivity,
                    "com.tekfirst.practical.fileprovider",
                    mediaFile);
            
            // 移除原flags,改用明确的权限授予
            mActivity.grantUriPermission(cameraComponent.getPackageName(), uriFile,
                    Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
            
            takeVideoIntent.putExtra(MediaStore.EXTRA_OUTPUT, uriFile);
            takeVideoIntent.putExtra(MediaStore.EXTRA_DURATION_LIMIT, 60);
            takeVideoIntent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1);
            startActivityForResult(takeVideoIntent, REQUEST_CODE_CAMERA);
        }
    }
}

同时确保FileProvider配置正确:

  • AndroidManifest.xml中声明Provider:
<provider
    android:name="androidx.core.content.FileProvider"
    android:authorities="com.tekfirst.practical.fileprovider"
    android:exported="false"
    android:grantUriPermissions="true">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/file_paths" />
</provider>
  • res/xml/file_paths.xml配置应用私有目录:
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-files-path name="video_files" path="Pictures/" />
</paths>

方案2:改用MediaStore插入视频(适配Scoped Storage)

若方案1仍无效,可通过MediaStore获取公共媒体库的Uri,让相机应用直接写入媒体库,避免权限问题:

private Uri createMediaStoreVideoUri() {
    ContentValues values = new ContentValues();
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
    String title = "VIDEO_" + bookedOutRA.getId() + "_" + timeStamp;
    
    values.put(MediaStore.Video.Media.TITLE, title);
    values.put(MediaStore.Video.Media.MIME_TYPE, "video/mp4");
    
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
        // Android 10+ 使用相对路径
        values.put(MediaStore.Video.Media.RELATIVE_PATH, 
            Environment.DIRECTORY_MOVIES + "/" + bookedOutRA.getId());
    } else {
        // 旧版本指定绝对路径
        File storageDir = new File(mActivity.getExternalFilesDir(Environment.DIRECTORY_MOVIES), 
            String.valueOf(bookedOutRA.getId()));
        if (!storageDir.exists()) storageDir.mkdirs();
        values.put(MediaStore.Video.Media.DATA, 
            new File(storageDir, title + ".mp4").getAbsolutePath());
    }
    
    return mActivity.getContentResolver().insert(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, values);
}

private void dispatchTakeVideoIntent() {
    Intent takeVideoIntent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
    if (takeVideoIntent.resolveActivity(mActivity.getPackageManager()) != null) {
        Uri videoUri = createMediaStoreVideoUri();
        if (videoUri != null) {
            takeVideoIntent.putExtra(MediaStore.EXTRA_OUTPUT, videoUri);
            takeVideoIntent.putExtra(MediaStore.EXTRA_DURATION_LIMIT, 60);
            takeVideoIntent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1);
            startActivityForResult(takeVideoIntent, REQUEST_CODE_CAMERA);
        }
    }
}

结果处理逻辑优化

无论哪种方案,都不要依赖返回的Intent数据,直接使用预先保存的文件路径或Uri:

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == REQUEST_CODE_CAMERA) {
        if (resultCode == Activity.RESULT_OK) {
            // 方案1:使用保存的getmCurrentPath
            if (!TextUtils.isEmpty(getmCurrentPath)) {
                File videoFile = new File(getmCurrentPath);
                if (videoFile.exists() && videoFile.length() > 0) {
                    // 处理录制完成的视频文件
                }
            }
            
            // 方案2:使用createMediaStoreVideoUri返回的videoUri
            // 可通过ContentResolver查询获取文件信息
        } else if (resultCode == Activity.RESULT_CANCELED) {
            // 清理空文件
            if (!TextUtils.isEmpty(getmCurrentPath)) {
                new File(getmCurrentPath).delete();
            }
        }
    }
}

内容的提问来源于stack exchange,提问作者Zain -ul-eman

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 09:08:11