You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

Xamarin.Forms中使用Signature Pad将签名保存至手机相册求助

如何将Signature Pad的签名流保存到手机相册

作为Xamarin新手,你已经成功获取到签名的流了,接下来要把它保存到相册——因为Xamarin.Forms没有跨平台的直接相册保存API,我们需要用依赖服务来调用原生平台的功能,下面是一步步的实现方案:

1. 在共享项目中定义统一接口

首先在你的共享项目里创建一个接口,用来标准化跨平台的保存方法:

public interface ISaveImageToGallery
{
    Task SaveStreamToGallery(Stream imageStream, string fileName, string albumName);
}

2. 实现Android平台的保存逻辑

Android平台需要处理权限和文件系统,先配置权限再写实现:

第一步:配置权限

打开Android项目的AndroidManifest.xml,添加对应权限(适配不同Android版本):

<!-- Android 9及以下需要的写权限 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- Android 10+ 需添加这个属性来兼容旧版存储逻辑 -->
<application android:requestLegacyExternalStorage="true" ...>

第二步:编写平台实现类

在Android项目中创建如下类:

[assembly: Dependency(typeof(SaveImageToGalleryAndroid))]
namespace YourAppName.Droid
{
    public class SaveImageToGalleryAndroid : ISaveImageToGallery
    {
        public async Task SaveStreamToGallery(Stream imageStream, string fileName, string albumName)
        {
            // Android 6+需要动态申请权限
            if (ContextCompat.CheckSelfPermission(Android.App.Application.Context, Manifest.Permission.WriteExternalStorage) != Permission.Granted)
            {
                ActivityCompat.RequestPermissions((Android.App.Activity)Xamarin.Essentials.Platform.CurrentActivity, new string[] { Manifest.Permission.WriteExternalStorage }, 1);
                await Task.Delay(1000); // 短暂等待权限申请结果
            }

            // 将流转换为Android Bitmap
            using var bitmap = await BitmapFactory.DecodeStreamAsync(imageStream);
            // 获取系统相册目录,创建自定义相册文件夹
            var picturesPath = Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryPictures).AbsolutePath;
            var albumPath = Path.Combine(picturesPath, albumName);
            Directory.CreateDirectory(albumPath);

            // 拼接文件路径
            var filePath = Path.Combine(albumPath, $"{fileName}.png");

            // 保存Bitmap到文件
            using var fileStream = new FileStream(filePath, FileMode.Create);
            await bitmap.CompressAsync(Bitmap.CompressFormat.Png, 100, fileStream);

            // 通知系统相册刷新,不然刚保存的图片可能看不到
            MediaScannerConnection.ScanFile(Android.App.Application.Context, new[] { filePath }, null, null);
        }
    }
}

3. 实现iOS平台的保存逻辑

iOS平台需要配置相册访问权限,再编写实现:

第一步:配置权限描述

打开iOS项目的Info.plist,添加相册权限说明:

<key>NSPhotoLibraryAddUsageDescription</key>
<string>需要访问相册来保存你的签名图片</string>

第二步:编写平台实现类

在iOS项目中创建如下类:

[assembly: Dependency(typeof(SaveImageToGalleryiOS))]
namespace YourAppName.iOS
{
    public class SaveImageToGalleryiOS : ISaveImageToGallery
    {
        public async Task SaveStreamToGallery(Stream imageStream, string fileName, string albumName)
        {
            // 申请相册访问权限
            var authStatus = await PHPhotoLibrary.RequestAuthorizationAsync();
            if (authStatus != PHAuthorizationStatus.Authorized)
            {
                await Application.Current.MainPage.DisplayAlert("提示", "需要开启相册权限才能保存签名", "确定");
                return;
            }

            // 将流转换为NSData,再转为UIImage
            using var data = NSData.FromStream(imageStream);
            var image = UIImage.LoadFromData(data);

            // 保存到系统相册
            await PHPhotoLibrary.SharedPhotoLibrary.PerformChangesAsync(() =>
            {
                var assetRequest = PHAssetCreationRequest.CreateAsset();
                assetRequest.AddResource(PHAssetResourceType.Photo, data, null);
            });
        }
    }
}

4. 修改MainPage的保存方法

现在回到你的MainPage.xaml.cs,修改SaveSignature方法来调用依赖服务:

public async void SaveSignature(object sender, EventArgs e)
{
    // 先检查是否有签名
    if (SignaturePAD.IsBlank)
    {
        await DisplayAlert("提示", "请先完成签名", "确定");
        return;
    }

    Stream imageStream = await SignaturePAD.GetImageStreamAsync(SignatureImageFormat.Png);
    var saveService = DependencyService.Get<ISaveImageToGallery>();

    try
    {
        // 调用保存方法,用时间戳做文件名避免重复
        await saveService.SaveStreamToGallery(imageStream, $"签名_{DateTime.Now:yyyyMMddHHmmss}", "我的签名");
        await DisplayAlert("成功", "签名已保存到相册", "确定");
    }
    catch (Exception ex)
    {
        await DisplayAlert("错误", $"保存失败:{ex.Message}", "确定");
    }
}

额外提示

  • 记得把代码里的YourAppName替换成你实际的项目名称;
  • Android 13及以上版本权限有更新,需要替换为READ_MEDIA_IMAGESWRITE_MEDIA_IMAGES,可以根据系统版本做适配;
  • 测试时尽量用真实设备,模拟器可能存在相册刷新延迟的问题。

内容的提问来源于stack exchange,提问作者Bartłomiej Klimek

火山引擎 最新活动