AutoFill 无处不在
AutoFill everywhere
2020年6月25日
一句话判断
iOS 14 把 AutoFill 从密码扩展到了所有类型的表单字段——姓名、邮箱、电话、信用卡、地址,甚至一次性验证码(OTP)。如果你的 App 有注册或支付流程,正确配置 AutoFill 能把用户填表时间缩短一半。
这场 Session 讲了什么
AutoFill 在 iOS 中已经存在多年,主要功能是自动填充保存在 iCloud Keychain 或第三方密码管理器中的账号密码。iOS 14 大幅扩展了 AutoFill 的覆盖范围。
Session 介绍了几个关键更新。第一,textContentType 属性新增了更多类型,包括 .oneTimeCode(一次性验证码)、.newPassword(新密码)、.URL 等。第二,键盘上方现在会自动建议验证码(SMS OTP),用户不需要切换 App 查看短信。第三,Security Framework 的 ASPasswordCredentialIdentity 和 ASPasswordCredential 让第三方密码管理器(如 1Password)可以更好地与 AutoFill 集成。第四,Safari 中的 Web 表单也支持了更丰富的 AutoFill 类型。
值得深挖的点
SMS 验证码自动填充
这是 iOS 14 中最实用的 AutoFill 新功能。当用户收到一条格式正确的 SMS 验证码消息时(如”Your code is 123456”),键盘上方会自动显示这个验证码,用户点击即可填入。要触发这个功能,你的 UITextField 的 textContentType 需要设置为 .oneTimeCode,消息格式需要包含纯数字的验证码。
新密码建议
iOS 14 可以在用户注册新账号时自动生成强密码。将 textContentType 设置为 .newPassword,系统会在键盘上方显示一个”使用强密码”的建议。用户选择后,密码会自动保存到 iCloud Keychain。下次登录时,AutoFill 会自动填入保存的密码。
代码片段
配置注册表单的 AutoFill
场景:为注册页面配置全面的 AutoFill 支持。
import UIKit
class RegistrationViewController: UIViewController {
@IBOutlet weak var nameField: UITextField!
@IBOutlet weak var emailField: UITextField!
@IBOutlet weak var phoneField: UITextField!
@IBOutlet weak var passwordField: UITextField!
@IBOutlet weak var confirmPasswordField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
configureAutoFill()
}
private func configureAutoFill() {
// 姓名:支持从通讯录自动填充
nameField.textContentType = .name
nameField.autocorrectionType = .no
// 邮箱:支持从账户信息自动填充
emailField.textContentType = .emailAddress
emailField.keyboardType = .emailAddress
emailField.autocapitalizationType = .none
// 电话号码
phoneField.textContentType = .telephoneNumber
phoneField.keyboardType = .phonePad
// 新密码:触发系统强密码建议
passwordField.textContentType = .newPassword
passwordField.isSecureTextEntry = true
// 确认密码
confirmPasswordField.textContentType = .newPassword
confirmPasswordField.isSecureTextEntry = true
}
}
配置验证码自动填充
场景:登录时自动填充 SMS 验证码。
class OTPVerificationViewController: UIViewController {
@IBOutlet weak var codeField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
configureOTPField()
}
private func configureOTPField() {
// 关键:设置 textContentType 为 oneTimeCode
codeField.textContentType = .oneTimeCode
codeField.keyboardType = .numberPad
// 监听填充事件
codeField.addTarget(self,
action: #selector(codeDidChange),
for: .editingChanged)
}
@objc private func codeDidChange() {
guard let code = codeField.text, code.count == 6 else { return }
// 验证码自动填充完成,自动提交
verifyCode(code)
}
private func verifyCode(_ code: String) {
// 向服务器验证
AuthService.verifyOTP(code: code) { success in
if success {
self.navigateToHome()
}
}
}
}
配置支付表单的 AutoFill
场景:为支付页面配置信用卡和地址自动填充。
class PaymentViewController: UIViewController {
@IBOutlet weak var cardNumberField: UITextField!
@IBOutlet weak var expiryField: UITextField!
@IBOutlet weak var cvvField: UITextField!
@IBOutlet weak var cardholderField: UITextField!
@IBOutlet weak var addressField: UITextField!
@IBOutlet weak var cityField: UITextField!
@IBOutlet weak var zipField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
configurePaymentAutoFill()
}
private func configurePaymentAutoFill() {
// 持卡人姓名
cardholderField.textContentType = .name
// 信用卡号
cardNumberField.textContentType = .creditCardNumber
cardNumberField.keyboardType = .numberPad
// 有效期(系统不提供自动填充,但可以手动输入)
expiryField.textContentType = .none
// CVV(安全码,不应该被自动填充)
cvvField.textContentType = .none
cvvField.isSecureTextEntry = true
// 地址信息
addressField.textContentType = .fullStreetAddress
cityField.textContentType = .addressCity
zipField.textContentType = .postalCode
}
}
为自定义密码管理器提供 AutoFill 支持
场景:通过 AuthenticationServices 框架让你的密码管理器参与 AutoFill。
import AuthenticationServices
// 在你的 App Extension 中提供密码凭据
class CredentialProviderViewController: ASCredentialProviderViewController {
// 提供凭据列表
override func prepareCredentialList(for serviceIdentifiers: [ASCredentialServiceIdentifier]) {
// 根据服务标识符查找保存的密码
let credentials = PasswordStore.shared.findCredentials(
for: serviceIdentifiers.first?.identifier ?? ""
)
// 显示凭据选择界面
displayCredentials(credentials)
}
// 用户选择了凭据后
override func provideCredentialWithoutUserInteraction(for credentialIdentity: ASPasswordCredentialIdentity) {
// 查找对应的密码
let credential = PasswordStore.shared.getCredential(
for: credentialIdentity.recordIdentifier
)
// 返回给系统
let passwordCredential = ASPasswordCredential(
user: credential.username,
password: credential.password
)
self.extensionContext.completeRequest(withSelectedCredential: passwordCredential)
}
}
最佳实践
已有项目:审查所有表单页面,为每个输入字段设置正确的 textContentType。最优先处理的是验证码字段(.oneTimeCode)和注册页面的密码字段(.newPassword)。这两个改动对用户体验的提升最明显。
新项目:从第一天就为所有表单字段设置 textContentType。这是零成本的优化——几行代码就能让用户享受系统级的自动填充体验。对于支付和注册等关键转化流程,确保 AutoFill 配置正确。
还有什么值得关注
- HTML 表单的 AutoFill 通过
autocomplete属性控制,不需要修改 iOS 代码。 - iOS 14 的 Safari 支持在 iframe 中使用 AutoFill,之前版本不支持。
- 密码自动填充的安全性保证:App 只能访问自己域名下的密码,不能跨域。