Android MediaRecorder启动失败:SYSTEM_CAMERA权限被拒
Xamarin.Forms安卓视频录制:MediaRecorder.start()失败,提示SYSTEM_CAMERA权限被拒
问题核心分析
- SYSTEM_CAMERA权限无效:该权限为系统级权限,第三方应用无法申请获取,你在清单中添加此权限不仅无用,还可能干扰系统权限检查逻辑,导致错误日志误导。
- 缺少摄像头预览Surface:Android系统要求MediaRecorder录制视频时必须绑定一个摄像头预览Surface(即使你不需要显示预览),未实现此步骤会直接导致
start()调用失败。
解决步骤
1. 清理不必要的权限
修改AndroidManifest.xml,移除android.permission.SYSTEM_CAMERA权限,保留必要权限:
<uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-feature android:name="android.hardware.camera" android:required="true" /> <uses-feature android:name="android.hardware.camera.autofocus" />
- Android 11及以上版本,若仅保存视频到应用私有目录,无需添加
WRITE_EXTERNAL_STORAGE权限。
2. 实现摄像头预览Surface(推荐使用CameraX)
Xamarin.Forms本身无内置摄像头预览控件,需通过DependencyService调用Android原生实现,推荐使用CameraX(Google官方推出的相机API,适配性更强):
步骤1:添加CameraX NuGet包
在Android项目中安装以下NuGet包:
Xamarin.AndroidX.Camera.CoreXamarin.AndroidX.Camera.Camera2Xamarin.AndroidX.Camera.LifecycleXamarin.AndroidX.Camera.View
步骤2:共享项目定义接口
public interface ICameraRecorderService { void InitializePreview(Android.Content.Context context); Task StartRecording(string outputFilePath); void StopRecording(); }
步骤3:Android项目实现接口
using Android.App; using Android.Content; using Android.OS; using Android.Views; using AndroidX.Camera.Core; using AndroidX.Camera.Lifecycle; using AndroidX.Camera.View; using AndroidX.Lifecycle; using Xamarin.Forms; [assembly: Dependency(typeof(AndroidCameraRecorderService))] namespace YourAppNamespace.Droid { public class AndroidCameraRecorderService : ICameraRecorderService, ILifecycleObserver { private PreviewView _cameraPreviewView; private VideoCapture _videoCapture; private Context _androidContext; public void InitializePreview(Context context) { _androidContext = context; var mainActivity = context as Activity; // 创建预览视图并添加到页面容器 _cameraPreviewView = new PreviewView(mainActivity) { LayoutParameters = new ViewGroup.LayoutParams( ViewGroup.LayoutParams.MatchParent, ViewGroup.LayoutParams.MatchParent) }; mainActivity.AddContentView(_cameraPreviewView, _cameraPreviewView.LayoutParameters); // 初始化CameraX var cameraProviderFuture = ProcessCameraProvider.GetInstance(mainActivity); cameraProviderFuture.AddListener(() => { var cameraProvider = cameraProviderFuture.Get(); BindCameraUseCases(cameraProvider); }, ContextCompat.MainExecutor(mainActivity)); } private void BindCameraUseCases(ProcessCameraProvider cameraProvider) { // 配置预览用例 var preview = new Preview.Builder().Build(); preview.SetSurfaceProvider(_cameraPreviewView.SurfaceProvider); // 配置视频录制用例 var videoCaptureConfig = new VideoCapture.Builder() .SetTargetRotation(_cameraPreviewView.Display.Rotation) .Build(); _videoCapture = videoCaptureConfig; // 绑定用例到相机生命周期 var cameraSelector = CameraSelector.DefaultBackCamera; try { cameraProvider.UnbindAll(); cameraProvider.BindToLifecycle( (LifecycleOwner)_androidContext, cameraSelector, preview, _videoCapture); } catch (Exception ex) { // 处理相机绑定异常,可输出日志调试 } } public async Task StartRecording(string outputFilePath) { if (_videoCapture == null) return; var outputFile = new Java.IO.File(outputFilePath); var outputOptions = new VideoCapture.OutputFileOptions.Builder(outputFile).Build(); await _videoCapture.RecordAsync( outputOptions, ContextCompat.MainExecutor(_androidContext), new VideoSaveCallback()); } public void StopRecording() { _videoCapture?.StopRecording(); } // 视频保存回调类 private class VideoSaveCallback : VideoCapture.OnVideoSavedCallback { public override void OnVideoSaved(VideoCapture.OutputFileResults outputFileResults) { // 视频保存成功逻辑 } public override void OnError(int videoCaptureError, string message, Java.Lang.Exception cause) { // 视频保存失败逻辑,可输出错误信息调试 } } } }
步骤4:Xamarin.Forms页面调用服务
protected override void OnAppearing() { base.OnAppearing(); // 初始化预览 var cameraService = DependencyService.Get<ICameraRecorderService>(); cameraService.InitializePreview(Android.App.Application.Context); } // 开始录制按钮点击事件 private async void StartRecordBtn_Clicked(object sender, EventArgs e) { // 视频保存路径(应用私有目录) var outputPath = Path.Combine( Android.OS.Environment.ExternalStorageDirectory.AbsolutePath, $"record_{DateTime.Now:yyyyMMddHHmmss}.mp4"); var cameraService = DependencyService.Get<ICameraRecorderService>(); await cameraService.StartRecording(outputPath); } // 停止录制按钮点击事件 private void StopRecordBtn_Clicked(object sender, EventArgs e) { var cameraService = DependencyService.Get<ICameraRecorderService>(); cameraService.StopRecording(); }
关键说明
- 若你坚持使用旧的
Camera+MediaRecorderAPI,同样需要创建SurfaceView并将摄像头预览输出到该Surface,再将Surface设置给MediaRecorder的SetPreviewDisplay()方法,但CameraX的适配性和稳定性远优于旧API。 - 权限申请需确保在运行时动态申请
CAMERA和RECORD_AUDIO权限,即使清单中已添加,Android 6.0及以上版本仍需动态授权。
内容的提问来源于stack exchange,提问作者TryingAgain
相关产品推荐
相关产品推荐

