LoginSignup
4
2

More than 5 years have passed since last update.

Xamarin.Authからの移行

Posted at

背景

Visual Studio for Mac を 2019 にアップデートしたら Xamarin.iOS のアプリが動かなくなった。

Xamarin.Auth の AccountStore.FindAccountsForServiceAsync を呼ぶだけでエラーが起きるようになっている。

https://github.com/xamarin/Xamarin.Auth/issues/370 にissueが上がっており、対策は

  1. Xamarin.iOSのダウングレード(12.2)
  2. Xamarin.Essentials の SecureStorage への移行。

のいずれか。

前者は影響範囲が全アプリに及ぶうえに、Xamarin.Auth のこのクラスは非推奨のため、後者を選択。

やり方

Migration Guide にあるように、次のようなヘルパークラスをつくって移行すればよい。

using Newtonsoft.Json;
using Xamarin.Auth;
using Xamarin.Essentials;

public class SecureStorageAccountStore
{
    public static async Task SaveAsync(Account account, string serviceId)
    {
        // Find existing accounts for the service
        var accounts = await FindAccountsForServiceAsync(serviceId);

        // Remove existing account with Id if exists
        accounts.RemoveAny(a => a.Username == account.Username);

        // Add account we are saving
        accounts.Add(account);

        // Serialize all the accounts to javascript
        var json = JsonConvert.SerializeObject(accounts);

        // Securely save the accounts for the given service
        await SecureStorage.SetAsync(serviceId, json);
    }

    public static async Task<List<Account>> FindAccountsForServiceAsync(string serviceId)
    {
        // Get the json for accounts for the service
        var json = await SecureStorage.GetAsync(serviceId);

        try {
            // Try to return deserialized list of accounts
            return JsonConvert.DeserializeObject<List<Account>>(json);
        } catch { }

        // If this fails, return an empty list
        return new List<Account>();
    }

    public static async Task MigrateAllAccountsAsync(string serviceId, IEnumerable<Account> accountStoreAccounts)
    {
        var wasMigrated = await SecureStorage.GetAsync("XamarinAuthAccountStoreMigrated", "0");

        if (wasMigrated == "1")
            return;

        await SecureStorage.SetAsync("XamarinAuthAccountStoreMigrated", "1");

        // Just in case, look at existing 'new' accounts
        var accounts = await FindAccountsForServiceAsync(serviceId);

        foreach (var account in accountStoreAccounts) {

            // Check if the new storage already has this account
            // We don't want to overwrite it if it does
            if (accounts.Any(a => a.Username == account.Username))
                continue;   

            // Add the account we are migrating
            accounts.Add(account);
        }

        // Serialize all the accounts to javascript
        var json = JsonConvert.SerializeObject(accounts);

        // Securely save the accounts for the given service
        await SecureStorage.SetAsync(serviceId, json);
    }
}

※ 上は挙げられているコードそのままだが、実際には System.Linq などの import をたす必要あり。

問題

が、結局この前後のデータのマイグレーションにも Find... が必要なため、この事態が起きてしまうということ。許容できない場合は Xamarin.Native でキーチェーンにアクセスして取り出す処理を書く必要がある。

もう一点、iOS SDK の問題だが、シミュレータ上では Entitlements.plist の編集が必要になる。通常(実機で使う場合)は不要のため、地味にストレスになる。

4
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
2