Как создать обработчик внутри потока, который не вызвал Looper.prepare() в мобильном приложении xamarin

У меня есть мобильное приложение с аутентификацией по отпечатку пальца, которое использует фреймворк xamarin. До сих пор все работало хорошо на всех устройствах, кроме Samsung Note 8. При попытке отладки этого устройства я получаю исключение Java.Lang.RuntimeException: не могу создать обработчик внутри потока, который не вызвал Looper.prepare(). Я понятия не имею, что это значит и как это исправить, потому что он хорошо работает с другими устройствами. Это дает исключение для строки keyGen.Init(keyGenSpec)

    static readonly string KEY_NAME = "YYYYYYY";

    static readonly string KEYSTORE_NAME = "AndroidKeyStore";

    static readonly string KEY_ALGORITHM = KeyProperties.KeyAlgorithmAes;
    static readonly string BLOCK_MODE = KeyProperties.BlockModeCbc;
    static readonly string ENCRYPTION_PADDING = KeyProperties.EncryptionPaddingPkcs7;

    static readonly string TRANSFORMATION = KEY_ALGORITHM + "/" +
                                            BLOCK_MODE + "/" +
                                            ENCRYPTION_PADDING;

    readonly KeyStore _keystore;

    public CryptoObjectHelper()
    {
        _keystore = KeyStore.GetInstance(KEYSTORE_NAME);
        _keystore.Load(null);
    }

    public FingerprintManagerCompat.CryptoObject BuildCryptoObject()
    {
        Cipher cipher = CreateCipher();
        return new FingerprintManagerCompat.CryptoObject(cipher);
    }

    Cipher CreateCipher(bool retry = true)
    {
        IKey key = GetKey();
        Cipher cipher = Cipher.GetInstance(TRANSFORMATION);
        try
        {
            cipher.Init(CipherMode.EncryptMode, key);
        }
        catch (KeyPermanentlyInvalidatedException e)
        {
            _keystore.DeleteEntry(KEY_NAME);
            if (retry)
            {
                CreateCipher(false);
            }
            else
            {
                throw new Exception("Could not create the cipher for fingerprint authentication.", e);
            }
        }
        return cipher;
    }

    IKey GetKey()
    {
        if (!_keystore.IsKeyEntry(KEY_NAME))
        {
            CreateKey();
        }

        IKey secretKey = _keystore.GetKey(KEY_NAME, null);
        return secretKey;
    }

    void CreateKey()
    {

            KeyGenerator keyGen = KeyGenerator.GetInstance(KeyProperties.KeyAlgorithmAes, KEYSTORE_NAME);
            KeyGenParameterSpec keyGenSpec =
                new KeyGenParameterSpec.Builder(KEY_NAME, KeyStorePurpose.Encrypt | KeyStorePurpose.Decrypt)
                    .SetBlockModes(BLOCK_MODE)
                    .SetEncryptionPaddings(ENCRYPTION_PADDING)
                    .SetUserAuthenticationRequired(true)
                    .Build();
            keyGen.Init(keyGenSpec);
            keyGen.GenerateKey();


    }

2 ответа

Решение

Не видя больше кода, трудно сказать, что происходит. Похоже, ваш код выполняется в фоновом потоке. Вы можете попробовать добавить android.os.Looper.Prepare() как первая строка внутри CreateKey(), Надеюсь, что это работает.

Я понятия не имею, что это значит и как это исправить, потому что он хорошо работает с другими устройствами. Это дает исключение для строки keyGen.Init(keyGenSpec)

Это похожая проблема здесь. И, как предложено, вы можете перехватить исключение и инициализировать ключ в потоке пользовательского интерфейса в соответствии с failedOnNote8:

failedOnNote8=false;
try{
    keyGen.Init(keyGenSpec);
}catch (Exception e) {
    if(e.getMessage() != null && e.getMessage().equals("Can't create handler inside thread that has not called Looper.prepare()"))  {
        failedOnNote8 = true;
    }
}
if(failedOnNote8)
{
   //try to init the key on UI Thread.
}
Другие вопросы по тегам