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

FirebaseDatabase.net在MAUI.NET中是否支持离线持久化?求实现代码示例

FirebaseDatabase.net在MAUI.NET中的离线持久化实现方案

一、核心结论

FirebaseDatabase.net这个第三方NuGet包本身没有内置MAUI平台专属的离线持久化机制,但可以通过手动结合本地缓存+同步逻辑来实现类似功能;如果追求更原生的离线体验,建议改用Firebase官方的MAUI绑定库。

二、手动实现离线持久化的代码片段

以下是基于SQLite本地缓存+FirebaseDatabase.net的实现示例:

1. 准备工作

先安装两个NuGet包:FirebaseDatabase.net 和 SQLite-net-pcl。

2. 定义本地缓存模型

using SQLite;

public class FirebaseLocalCache
{
    [PrimaryKey, AutoIncrement]
    public int Id { get; set; }
    public string FirebasePath { get; set; } // 对应Firebase节点路径
    public string DataJson { get; set; } // 缓存的数据JSON
    public DateTime LastUpdated { get; set; }
    public bool IsPendingSync { get; set; } // 标记是否待同步到Firebase
}

3. 封装离线操作服务

using Firebase.Database;
using Firebase.Database.Query;
using Newtonsoft.Json;
using SQLite;

public class FirebaseOfflineManager
{
    private readonly FirebaseClient _firebaseClient;
    private readonly SQLiteAsyncConnection _localDb;

    public FirebaseOfflineManager(string firebaseDbUrl)
    {
        _firebaseClient = new FirebaseClient(firebaseDbUrl);
        // 初始化本地SQLite数据库
        var dbPath = Path.Combine(FileSystem.AppDataDirectory, "firebase_offline_cache.db");
        _localDb = new SQLiteAsyncConnection(dbPath);
        _localDb.CreateTableAsync<FirebaseLocalCache>().Wait();
    }

    // 读取数据:在线优先拉取最新数据,离线读取本地缓存
    public async Task<T> FetchDataAsync<T>(string nodePath)
    {
        try
        {
            // 尝试从Firebase在线获取
            var remoteData = await _firebaseClient.Child(nodePath).OnceSingleAsync<T>();
            // 更新本地缓存
            await UpdateLocalCache(nodePath, remoteData, false);
            return remoteData;
        }
        catch
        {
            // 离线时读取本地缓存
            var cacheItem = await _localDb.Table<FirebaseLocalCache>()
                .FirstOrDefaultAsync(c => c.FirebasePath == nodePath);
            
            if(cacheItem != null)
            {
                return JsonConvert.DeserializeObject<T>(cacheItem.DataJson);
            }
            throw new InvalidOperationException("离线状态下无可用缓存数据");
        }
    }

    // 写入数据:先存本地缓存,在线时同步到Firebase
    public async Task SaveDataAsync<T>(string nodePath, T data)
    {
        var dataJson = JsonConvert.SerializeObject(data);
        // 更新本地缓存并标记待同步
        await UpdateLocalCache(nodePath, data, true);

        try
        {
            // 在线时同步到Firebase
            await _firebaseClient.Child(nodePath).PutAsync(data);
            // 同步成功后清除待同步标记
            var cacheItem = await _localDb.Table<FirebaseLocalCache>()
                .FirstOrDefaultAsync(c => c.FirebasePath == nodePath);
            if(cacheItem != null)
            {
                cacheItem.IsPendingSync = false;
                await _localDb.UpdateAsync(cacheItem);
            }
        }
        catch
        {
            // 离线时忽略,后续网络恢复再同步
        }
    }

    // 网络恢复时同步本地待上传数据
    public async Task SyncPendingChangesAsync()
    {
        var pendingItems = await _localDb.Table<FirebaseLocalCache>()
            .Where(c => c.IsPendingSync).ToListAsync();
        
        foreach(var item in pendingItems)
        {
            try
            {
                var data = JsonConvert.DeserializeObject(item.DataJson);
                await _firebaseClient.Child(item.FirebasePath).PutAsync(data);
                item.IsPendingSync = false;
                await _localDb.UpdateAsync(item);
            }
            catch
            {
                // 同步失败,保留标记下次重试
            }
        }
    }

    private async Task UpdateLocalCache<T>(string path, T data, bool isPending)
    {
        var dataJson = JsonConvert.SerializeObject(data);
        var existingCache = await _localDb.Table<FirebaseLocalCache>()
            .FirstOrDefaultAsync(c => c.FirebasePath == path);
        
        if(existingCache != null)
        {
            existingCache.DataJson = dataJson;
            existingCache.LastUpdated = DateTime.Now;
            existingCache.IsPendingSync = isPending;
            await _localDb.UpdateAsync(existingCache);
        }
        else
        {
            await _localDb.InsertAsync(new FirebaseLocalCache
            {
                FirebasePath = path,
                DataJson = dataJson,
                LastUpdated = DateTime.Now,
                IsPendingSync = isPending
            });
        }
    }
}

4. 在MAUI中使用服务

在MauiProgram.cs注册服务:

builder.Services.AddSingleton<FirebaseOfflineManager>(sp => 
    new FirebaseOfflineManager("你的Firebase数据库URL"));

在页面中注入并使用,同时监听网络状态变化触发同步:

private readonly FirebaseOfflineManager _firebaseManager;

public MainPage(FirebaseOfflineManager firebaseManager)
{
    InitializeComponent();
    _firebaseManager = firebaseManager;
}

protected override void OnAppearing()
{
    base.OnAppearing();
    Connectivity.ConnectivityChanged += OnConnectivityChanged;
}

protected override void OnDisappearing()
{
    base.OnDisappearing();
    Connectivity.ConnectivityChanged -= OnConnectivityChanged;
}

private async void OnConnectivityChanged(object sender, ConnectivityChangedEventArgs e)
{
    if(e.NetworkAccess == NetworkAccess.Internet)
    {
        await _firebaseManager.SyncPendingChangesAsync();
    }
}

// 示例:读取数据
private async void ReadButton_Clicked(object sender, EventArgs e)
{
    try
    {
        var userData = await _firebaseManager.FetchDataAsync<User>("users/user123");
        // 处理数据
    }
    catch(Exception ex)
    {
        // 处理异常
    }
}

三、更简便的替代方案

如果手动实现过于繁琐,建议使用Plugin.Firebase这个NuGet包(Firebase官方的MAUI绑定库),它内置了原生的离线持久化功能:

  1. 安装Plugin.Firebase及对应子包(如Plugin.Firebase.Database)
  2. 配置Android的google-services.json和iOS的GoogleService-Info.plist
  3. 启用离线持久化:
using Plugin.Firebase.Database;

var database = CrossFirebaseDatabase.Current.Instance;
database.SetPersistenceEnabled(true); // 开启官方离线持久化

该方案会自动处理本地缓存、离线读写、网络恢复后的同步,无需手动编写缓存逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 20:47:14