Xamarin.Forms相机功能在VIVO 1904设备上无法正常工作求助
Xamarin.Forms拍照功能在VIVO 1904设备上失效的解决方案
问题背景
使用Xamarin.Forms开发的应用,拍照功能在多数设备上运行正常,但在VIVO 1904设备上无法工作。已在项目中添加Camera、WRITE_EXTERNAL_STORAGE、READ_EXTERNAL_STORAGE权限,核心实现代码如下:
public async void Capture() { try { await CrossMedia.Current.Initialize(); var cameraStatus = await CrossPermissions.Current.CheckPermissionStatusAsync(Permission.Camera); var storageStatus = await CrossPermissions.Current.CheckPermissionStatusAsync(Permission.Storage); if (cameraStatus != PermissionStatus.Granted || storageStatus != PermissionStatus.Granted) { var results = await CrossPermissions.Current.RequestPermissionsAsync(new[] { Permission.Camera, Permission.Storage }); cameraStatus = results[Permission.Camera]; storageStatus = results[Permission.Storage]; } var D = await DisplayActionSheet("Select action", "Cancel", null, new string[] { "Gallery", "Camera" }); if (D == "Camera") { if (!CrossMedia.Current.IsCameraAvailable || !CrossMedia.Current.IsTakePhotoSupported) { await DisplayAlert("No Camera", "No camera available.", "OK"); return; } var requestedPermissions = await CrossPermissions.Current.RequestPermissionsAsync(Permission.Camera); var requestedPermissionStatus = requestedPermissions[Permission.Camera]; if (requestedPermissionStatus == Plugin.Permissions.Abstractions.PermissionStatus.Granted) { var file = await CrossMedia.Current.TakePhotoAsync(new Plugin.Media.Abstractions.StoreCameraMediaOptions { Directory = "Sample", Name = "Attach.jpg", PhotoSize = Plugin.Media.Abstractions.PhotoSize.Medium, AllowCropping = true }); if (file == null) { return; } pathList.Add(new Path() { path = file.Path }); attachednolbl.Text = pathList.Count.ToString(); } #region xamarin essential //var photo = await MediaPicker.CapturePhotoAsync(); //if (photo == null) //{ // return; //} //// save the file into local storage //var newFile = System.IO.Path.Combine(FileSystem.CacheDirectory, photo.FileName); //if (newFile == null) //{ // return; //} //using (var stream = await photo.OpenReadAsync()) //{ // using (var newStream = System.IO.File.OpenWrite(newFile)) // await stream.CopyToAsync(newStream); // long imageLength = stream.Length; // byte[] imageBytes = new byte[imageLength]; // await stream.ReadAsync(imageBytes, 0, (int)imageLength); // var pathStream = imageBytes; // pathList.Add(new Path() { path = newFile }); // attachednolbl.Text = pathList.Count.ToString(); //} #endregion } if (D == "Gallery") { string _imageSelected = string.Empty; if (Xamarin.Essentials.DeviceInfo.Platform == Xamarin.Essentials.DevicePlatform.Android) { await DependencyService.Get<IMediaService>().OpenGallery(); MessagingCenter.Subscribe<App, List<string>>((App)Xamarin.Forms.Application.Current, "ImagesSelected", async (s, images) => { var ClickedOrSelectedImages = new Dictionary<string, byte[]>(); var selectedImages = new ObservableCollection<SelectedImages>(); // int i = 0; foreach (var item in images) { pathList.Add(new Path() { path = item }); } attachednolbl.Text = pathList.Count.ToString(); MessagingCenter.Unsubscribe<App, List<string>>((App)Xamarin.Forms.Application.Current, "ImagesSelected"); }); } else { var media = CrossMedia.Current; var file = await CrossMedia.Current.PickPhotosAsync(new Plugin.Media.Abstractions.PickMediaOptions { PhotoSize = PhotoSize.Small, }); if (file == null) { return; } else { foreach (var item in file) { pathList.Add(new Path() { path = item.Path }); } attachednolbl.Text = pathList.Count.ToString(); } } #region xamarin essential //var result = await FilePicker.PickMultipleAsync(PickOptions.Images); //foreach (var photo in result) //{ // if (photo == null) // { // return; // } // // save the file into local storage // var newFile = System.IO.Path.Combine(FileSystem.CacheDirectory, photo.FileName); // using (var stream = await photo.OpenReadAsync()) // { // long imageLength = stream.Length; // byte[] imageBytes = new byte[imageLength]; // await stream.ReadAsync(imageBytes, 0, (int)imageLength); // var pathStream = imageBytes; // // var image = System.Convert.ToBase64String(pathStream); // pathList.Add(new Path() { path = photo.FullPath }); // } //} //attachednolbl.Text = pathList.Count.ToString(); #endregion } } catch (Exception ex) { DependencyService.Get<IToast>().Show(ex.Message.ToString()); Console.WriteLine(ex.Message.ToString()); } }
解决方案
1. 适配VIVO设备的权限管控策略
VIVO部分机型对权限的管控比常规Android设备更严格,需补充以下配置:
- 在
AndroidManifest.xml中添加相机硬件特性声明,确保权限生效:<uses-permission android:name="android.permission.CAMERA" /> <uses-feature android:name="android.hardware.camera" android:required="true" /> <uses-feature android:name="android.hardware.camera.autofocus" android:required="false" /> - 手动检查VIVO设备的应用权限设置,确认"相机"和"存储"权限已完全开启(部分VIVO机型会拆分权限为前台/后台使用,需全部允许)。
2. 优化权限申请逻辑
代码中存在重复申请相机权限的冗余逻辑,且未处理权限申请失败的场景,调整如下:
- 移除相机分支内重复的权限申请代码,统一在方法开头完成权限校验
- 增加权限申请失败后的提示与引导:
// 替换原相机分支的权限判断逻辑 if (cameraStatus != PermissionStatus.Granted) { await DisplayAlert("权限不足", "需要相机权限才能拍照,请前往设置开启", "确定"); await CrossPermissions.Current.OpenAppSettings(); return; }
3. 适配Android存储机制
VIVO 1904基于Android 9/10,需适配存储权限变化:
- 若目标SDK版本≥29,在
AndroidManifest.xml的application标签中添加旧存储模式兼容配置:<application ... android:requestLegacyExternalStorage="true"> - 避免使用自定义目录
"Sample",改用系统推荐的公共目录,降低存储访问限制:var file = await CrossMedia.Current.TakePhotoAsync(new Plugin.Media.Abstractions.StoreCameraMediaOptions { Directory = Plugin.Media.Abstractions.MediaDirectory.Pictures, Name = $"Attach_{DateTime.Now.Ticks}.jpg", PhotoSize = Plugin.Media.Abstractions.PhotoSize.Medium, AllowCropping = true });
4. 排查系统裁剪兼容性问题
部分VIVO机型的系统裁剪组件与CrossMedia插件存在兼容性冲突,可先禁用裁剪功能测试:
AllowCropping = false
若禁用后拍照功能恢复,可改用第三方裁剪控件(如FFImageLoading.Transformations)替代系统裁剪。
5. 升级插件版本
旧版本的Plugin.Media和Plugin.Permissions可能未适配VIVO新机型,将插件升级到最新稳定版:
- 通过NuGet包管理器更新两个插件至最新版本
- 确保Android项目的
MainActivity中已正确初始化插件(若有初始化要求)
内容的提问来源于stack exchange,提问作者Kirti Zare
相关产品推荐
相关产品推荐

