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

Xamarin Forms迁移MAUI后,SecureStorage.GetAsync读取旧值返回null

解决方案:Xamarin Forms迁移MAUI后SecureStorage读取旧数据问题

Android 端处理

MAUI 的 SecureStorage 在 Android 上默认使用了和 Xamarin Forms 不同的存储容器,即便 App ID 一致,也会导致无法读取旧数据。可以通过自定义 ISecureStorage 实现兼容旧存储:

  • 创建自定义 SecureStorage 实现,直接访问 Xamarin Forms 曾使用的 KeyStore 条目:

    using Android.Security.Keystore;
    using Java.Security;
    using Javax.Crypto;
    using Javax.Crypto.Spec;
    using System.Text;
    
    public class LegacySecureStorage : ISecureStorage
    {
        private const string KeyStoreName = "AndroidKeyStore";
        private const string LegacyAliasPrefix = "Xamarin.Forms.SecureStorage_";
    
        public async Task<string> GetAsync(string key)
        {
            try
            {
                KeyStore keyStore = KeyStore.GetInstance(KeyStoreName);
                keyStore.Load(null);
    
                string legacyAlias = LegacyAliasPrefix + key;
                if (!keyStore.ContainsAlias(legacyAlias))
                    return null;
    
                var entry = keyStore.GetEntry(legacyAlias, null) as KeyStore.SecretKeyEntry;
                if (entry == null)
                    return null;
    
                SecretKey secretKey = entry.SecretKey;
                Cipher cipher = Cipher.GetInstance("AES/GCM/NoPadding");
                cipher.Init(Cipher.DecryptMode, secretKey);
    
                var prefs = Android.App.Application.Context.GetSharedPreferences("Xamarin.Forms.SecureStorage", Android.Content.FileCreationMode.Private);
                string encryptedValue = prefs.GetString(key, null);
                if (string.IsNullOrEmpty(encryptedValue))
                    return null;
    
                byte[] encryptedBytes = Convert.FromBase64String(encryptedValue);
                byte[] decryptedBytes = cipher.DoFinal(encryptedBytes);
                return Encoding.UTF8.GetString(decryptedBytes);
            }
            catch (Exception)
            {
                return null;
            }
        }
    
        public Task SetAsync(string key, string value) => SecureStorage.Default.SetAsync(key, value);
        public Task RemoveAsync(string key) => SecureStorage.Default.RemoveAsync(key);
        public Task RemoveAllAsync() => SecureStorage.Default.RemoveAllAsync();
    }
    
  • 在 MAUI 启动时注册这个自定义实现:

    // 在 MauiProgram.cs 的 CreateMauiApp 方法中
    builder.Services.AddSingleton<ISecureStorage, LegacySecureStorage>();
    

此方案既可以读取旧的Xamarin Forms存储数据,新数据也会用MAUI默认方式存储。

iOS 端处理

TestFlight 构建读取失败原因

本地部署可读取但TestFlight不行,是因为TestFlight构建启用了App Attest或数据隔离相关安全机制,导致MAUI的SecureStorage无法访问Xamarin Forms存在NSUserDefaults里的数据(Xamarin Forms的SecureStorage在iOS底层就是NSUserDefaults,仅添加了前缀)。

兼容方案

  1. 兼容旧数据读取逻辑:
    读取数据时先尝试MAUI的SecureStorage.GetAsync,若返回null,再用NSUserDefaults读取旧数据,读取成功后同步到MAUI的SecureStorage中:

    public async Task<string> GetLegacyOrNewValue(string key)
    {
        string value = await SecureStorage.Default.GetAsync(key);
        if (!string.IsNullOrEmpty(value))
            return value;
    
        string legacyKey = $"Xamarin.Forms.SecureStorage_{key}";
        var defaults = Foundation.NSUserDefaults.StandardUserDefaults;
        string legacyValue = defaults.StringForKey(legacyKey);
        if (!string.IsNullOrEmpty(legacyValue))
        {
            await SecureStorage.Default.SetAsync(key, legacyValue);
            defaults.RemoveObject(legacyKey);
            defaults.Synchronize();
        }
        return legacyValue;
    }
    
  2. 配置Entitlements.plist:

    • 避免添加com.apple.security.application-groups(除非业务必需),否则旧数据不在该组内会无法读取。
    • 确保keychain-access-groups包含App ID前缀,与Xamarin Forms配置一致:
      <key>keychain-access-groups</key>
      <array>
          <string>$(AppIdentifierPrefix)com.yourcompany.yourapp</string>
      </array>
      

通用建议

  • 所有读取操作先兼容旧数据,读取成功后同步到MAUI存储系统,后续统一使用MAUI的SecureStorage方法,减少重复兼容逻辑。
  • 测试时覆盖完整升级场景:从Xamarin Forms正式版本升级到MAUI的TestFlight/正式版本,验证数据读取是否正常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 17:00:24