Section 7/161 menit
7. Conditional UI dan AutoFill Integration
7. Conditional UI dan AutoFill Integration
Cara Kerja AutoFill Passkey
AutoFill passkey muncul di atas keyboard saat field login aktif. Ini adalah "passive" request — tidak ada modal sheet yang muncul. User melihat passkey di toolbar keyboard dan bisa tap untuk autentikasi.
swift
┌───────────────────────────┐
│ Username: ___________ │
│ Password: ___________ │
│ │
│ [Log in] │
└───────────────────────────┘
┌───────────────────────────┐
│ 🔑 example.com Passkey > │ ← AutoFill bar
├───────────────────────────┤
│ Q W E R T Y U I O P │
│ ... │
└───────────────────────────┘
Implementasi yang Benar
swift
import AuthenticationServices
class LoginViewController: UIViewController {
@IBOutlet weak var usernameField: UITextField!
@IBOutlet weak var passwordField: UITextField!
private var conditionalController: ASAuthorizationController?
private var conditionalChallenge: Data = Data()
override func viewDidLoad() {
super.viewDidLoad()
// Aktifkan AutoFill untuk text fields
usernameField.textContentType = .username
passwordField.textContentType = .password
// Fetch challenge dari server dan mulai conditional request
Task {
await beginConditionalSignIn()
}
}
private func beginConditionalSignIn() async {
do {
// Fetch challenge dari server (non-blocking untuk UI)
conditionalChallenge = try await server.fetchChallenge()
let provider = ASAuthorizationPlatformPublicKeyCredentialProvider(
relyingPartyIdentifier: "example.com"
)
let request = provider.createCredentialAssertionRequest(
challenge: conditionalChallenge
)
// Tambah password request agar saved passwords juga muncul di AutoFill
let passwordProvider = ASAuthorizationPasswordProvider()
let passwordRequest = passwordProvider.createRequest()
let controller = ASAuthorizationController(authorizationRequests: [
request,
passwordRequest
])
controller.delegate = self
controller.presentationContextProvider = self
// KUNCI: performAutoFillAssistedRequests, bukan performRequests
controller.performAutoFillAssistedRequests()
conditionalController = controller // Retain
} catch {
// Gagal fetch challenge — AutoFill tidak aktif, tapi login manual masih bisa
print("Conditional sign-in tidak tersedia: \(error)")
}
}
// Saat user tap tombol Login manual (non-AutoFill)
@IBAction func loginButtonTapped() {
// Cancel conditional request yang sedang berjalan
conditionalController = nil
// Mulai modal sign-in (akan tampilkan sheet)
Task {
do {
let challenge = try await server.fetchChallenge()
try await performModalSignIn(challenge: challenge)
} catch {
showError(error)
}
}
}
private func performModalSignIn(challenge: Data) async throws {
let provider = ASAuthorizationPlatformPublicKeyCredentialProvider(
relyingPartyIdentifier: "example.com"
)
let request = provider.createCredentialAssertionRequest(challenge: challenge)
let controller = ASAuthorizationController(authorizationRequests: [request])
controller.delegate = self
controller.presentationContextProvider = self
controller.performRequests() // Modal sheet
}
}