import 'package:flutter/services.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; /// `errSecDuplicateItem`: the iOS keychain refused to add an item that is /// already there. const int kErrSecDuplicateItem = -25299; /// Whether [error] is the iOS keychain's "item already exists" failure. /// flutter_secure_storage surfaces it as a PlatformException whose details /// (and message) carry the OSStatus. bool isKeychainDuplicateItem(Object error) { if (error is! PlatformException) return false; if (error.details == kErrSecDuplicateItem) return true; return error.message?.contains('$kErrSecDuplicateItem') ?? false; } extension KeychainWrite on FlutterSecureStorage { /// [write] that survives `errSecDuplicateItem`. The plugin's iOS write is /// check-then-add/update and not atomic: a concurrent write to the same key /// — or an existence check that itself failed (seen with the disk full) — /// ends in SecItemAdd on an existing item. The second attempt finds the /// item and updates it. Future writeRetrying({ required String key, required String value, }) async { try { await write(key: key, value: value); } on PlatformException catch (e) { if (!isKeychainDuplicateItem(e)) rethrow; await write(key: key, value: value); } } }