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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 09:54:50