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

MAUI.NET安卓11+:如何将应用内SQLite数据库复制到下载目录?

MAUI Android SQLite 备份/恢复实现(适配安卓11+)

1. 权限配置

在Platforms/Android/AndroidManifest.xml中添加以下权限:

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="29" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />

2. 核心实现代码

创建BackupService类封装备份恢复逻辑:

using System.IO;
using Microsoft.Maui.Storage;
using Android.Content;
using Android.OS;

public class BackupService
{
    private readonly string _dbFileName = "mydb.db";
    private string _dbPath => Path.Combine(FileSystem.AppDataDirectory, _dbFileName);

    // 导出数据库到下载目录
    public async Task<bool> ExportDatabaseAsync()
    {
        try
        {
            if (!await CheckAndRequestPermissionsAsync())
                return false;

            var downloadFolder = await FileSystem.GetFolderAsync(SpecialFolder.Downloads);
            var backupPath = Path.Combine(downloadFolder.Path, $"mydb_backup_{DateTime.Now:yyyyMMddHHmmss}.db");

            File.Copy(_dbPath, backupPath, overwrite: true);
            return true;
        }
        catch (Exception ex)
        {
            Console.WriteLine($"导出失败: {ex.Message}");
            return false;
        }
    }

    // 从用户选择的备份文件恢复数据库
    public async Task<bool> RestoreDatabaseAsync()
    {
        try
        {
            if (!await CheckAndRequestPermissionsAsync())
                return false;

            var pickResult = await FilePicker.Default.PickAsync(new PickOptions
            {
                PickerTitle = "选择数据库备份文件",
                FileTypes = new FilePickerFileType(new Dictionary<DevicePlatform, IEnumerable<string>>
                {
                    { DevicePlatform.Android, new[] { "application/x-sqlite3" } }
                })
            });

            if (pickResult == null)
                return false;

            // 注意:这里需关闭所有已打开的数据库连接,避免文件被占用
            // 示例(若用SQLite-net):await _sqliteConnection.CloseAsync();

            using (var sourceStream = await pickResult.OpenReadAsync())
            using (var targetStream = File.OpenWrite(_dbPath))
            {
                await sourceStream.CopyToAsync(targetStream);
            }

            // 恢复后重新打开数据库连接(若需要)
            // 示例:await _sqliteConnection.OpenAsync();

            return true;
        }
        catch (Exception ex)
        {
            Console.WriteLine($"恢复失败: {ex.Message}");
            return false;
        }
    }

    // 检查并请求权限
    private async Task<bool> CheckAndRequestPermissionsAsync()
    {
        if (DeviceInfo.Platform != DevicePlatform.Android)
            return true;

        var androidVersion = (int)Build.VERSION.SdkInt;

        if (androidVersion >= 30)
        {
            if (!Android.OS.Environment.IsExternalStorageManager)
            {
                var intent = new Intent(Android.Provider.Settings.ActionManageAppAllFilesAccessPermission);
                intent.AddCategory(Intent.CategoryDefault);
                intent.SetData(Android.Net.Uri.Parse($"package:{Android.App.Application.Context.PackageName}"));
                await MainThread.InvokeOnMainThreadAsync(() =>
                {
                    Android.App.Application.Context.StartActivity(intent);
                });
                await Task.Delay(2000); // 等待用户完成权限设置
                return Android.OS.Environment.IsExternalStorageManager;
            }
            return true;
        }
        else
        {
            var statusRead = await Permissions.CheckStatusAsync<Permissions.StorageRead>();
            var statusWrite = await Permissions.CheckStatusAsync<Permissions.StorageWrite>();

            if (statusRead != PermissionStatus.Granted || statusWrite != PermissionStatus.Granted)
            {
                var result = await Permissions.RequestAsync<Permissions.StorageWrite>();
                return result == PermissionStatus.Granted;
            }
            return true;
        }
    }
}

3. 页面调用示例

在MAUI页面中绑定按钮事件:

private readonly BackupService _backupService = new BackupService();

private async void OnExportBtnClicked(object sender, EventArgs e)
{
    var success = await _backupService.ExportDatabaseAsync();
    await DisplayAlert("提示", success ? "备份成功" : "备份失败", "确定");
}

private async void OnRestoreBtnClicked(object sender, EventArgs e)
{
    var success = await _backupService.RestoreDatabaseAsync();
    await DisplayAlert("提示", success ? "恢复成功" : "恢复失败", "确定");
}

4. 关键注意事项

  • 数据库连接管理:恢复操作前必须关闭所有数据库连接,否则会因文件被占用导致复制失败,需根据你使用的SQLite库(如SQLite-net、Microsoft.Data.Sqlite)调整对应逻辑。
  • 权限处理:安卓11+需MANAGE_EXTERNAL_STORAGE权限,代码会自动引导用户到应用权限设置页面开启。
  • 备份命名:代码自动添加时间戳避免覆盖备份文件,可根据需求调整命名规则。

内容的提问来源于stack exchange,提问作者user18107302

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 22:21:05