iOS 跨平台帐号密码整合|提升 APP 与网站登入体验,快速自动填入密码
解决 APP 与网站帐号密码分离问题,透过 iOS Associated Domains 与 Shared Web Credentials 技术,自动带入已存密码,减少重复输入痛点,提升用户登入速度与便利性,强化跨平台使用者体验。
Click here to view the English version of this article.
點擊這裡查看本文章正體中文版本。
基于 SEO 考量,本文标题与描述经 AI 调整,原始版本请参考内文。
iOS 跨平台帐号密码整合,加强登入体验
除 Sign in with Apple 也值得加入的功能
Photo by Dan Nelson
功能
在同时有网站又有 APP 的服务中最常遇到的问题就是使用者在网站登入注册过,且有记忆密码;但被引导安装 APP 后,打开登入要从头输入帐号密码非常不方便;此功能就是能将已存在在手机的帐号密码自动带入到与网站关联的 APP 之中,加速使用者登入流程。
效果图
不啰唆,先上完成效果图;第一眼看到可能会以为是 iOS ≥ 11 Password AutoFill 功能;不过请您仔细看,键盘并没有跳出来,而且我是点击「选择已存密码」按钮才跳出帐号密码选择视窗的。
既然提到了 Password AutoFill 那就先让我卖个关子,先介绍 Password AutoFill 和如何设置吧!
Password AutoFill
支援度:iOS ≥ 11
到如今已经 iOS 14 了,这个功能已经非常常见没什么特别的;在 APP 中的帐号密码登入页,叫出键盘输入时可以快速选择网站版服务的帐号密码,选择后就能自动带入,快速登入!
那么 APP 与 Web 之间是如何相认的呢?
Associated Domains!我们在 APP 中指定 Associated Domains 并在网站上上传 apple-app-site-association 档案,两边就能相认。
1.在专案设定中的「Signing & Capabilities」-> 左上「+ Capabilities」->「Associated Domains」
新增 webcredentials:你的网站域名
(ex: webcredentials:google.com
)。
2.进入 苹果开发者后台
在「 Membership 」Tab 地方记录下「 Team ID 」
3.进入「Certificates, Identifiers & Profiles」->「Identifiers」-> 找到你的专案 -> 打开「Associated Domains」功能
APP 端设定完成!
4.Web网站端设定
建立一个名为「 apple-app-site-association 」的档案(无副档名),使用文字编辑器编辑,并输入以下内容:
1
2
3
4
5
6
7
{
"webcredentials": {
"apps": [
"TeamID.BundleId"
]
}
}
将 TeamID.BundleId
换成你的专案设定 (ex: TeamID = ABCD
, BundleID = li.zhgchg.demoapp
=> ABCD.li.zhgchg.demoapp
)
将此档案上传到网站 根目录
或 /.well-known
目录下,假设你的 webcredentials 网站域名
是设 google.com
则此档案就要是 google.com/apple-app-site-association
或 google.com/.well-know/apple-app-site-association
有办法存取到的。
补充:Subdomains
摘录官方文件,如果是 subdomains 则都须列在 Associated Domains 之中。
Web 端设定完成!
补充:applinks
这边有发现如果有设过 universal link applinks
,其实不用再多加 webcredentials
部分也能有效果;但我们还是照文件来吧,难保之后不会有其他问题。
回到程式
Code 部分,我们只需要将 TextField 设为 :
1
2
usernameTextField.textContentType = .username
passwordTextField.textContentType = .password
如果是新注册,密码确认栏位可使用:
1
repeatPasswordTextField.textContentType = .newPassword
这时候再重 Build & Run APP 后,在输入帐号时键盘上方就会出现同个网站下已存密码的选项了。
完成!
没出现?
可能是没打开自动填写密码功能(模拟器预设是关闭),请到「设定」->「密码」->「自动填写密码」->打开「自动填写密码」。
抑或是该网站没有已存在的密码,一样可在「设定」->「密码」-> 右上角「+ 新增」-> 新增。
进入主题
前菜 Password AutoFill 介绍完之后,再来进入本篇主题;如何达到效果图中的效果呢。
Shared Web Credentials
始于 iOS 8.0 只是之前很少看到 APP 使用,早在 Password AutoFill 出来之前其实就能使用此 API 整合网站帐号密码让使用者快速选择。
Shared Web Credentials 除了能读取帐号密码,还能新增帐号密码、对已存的帐号密码进行修改、删除。
设定
⚠️ 设定部分一样要设好 Associated Domains,同前述 Password AutoFill 设定。
所以可以说是 Password AutoFill 功能的加强版!!
因为一样要先设好 Password AutoFill 需要的环境才能使用此「进阶」功能。
读取
读取使用 SecRequestSharedWebCredential
方法进行操作:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
SecRequestSharedWebCredential(nil, nil) { (credentials, error) in
guard error == nil else {
DispatchQueue.main.async {
//alert error
}
return
}
guard CFArrayGetCount(credentials) > 0,
let dict = unsafeBitCast(CFArrayGetValueAtIndex(credentials, 0), to: CFDictionary.self) as? Dictionary<String, String>,
let account = dict[kSecAttrAccount as String],
let password = dict[kSecSharedPassword as String] else {
DispatchQueue.main.async {
//alert error
}
return
}
DispatchQueue.main.async {
//fill account,password to textfield
}
}
SecRequestSharedWebCredential(fqdn, account, completionHandler)
fqdn 如果有多个
webcredentials
domain 可以指定某一个,或使用 null 不指定account 指定要查某一个帐号,使用 null 不指定
效果图。(你可能有发现跟开始的效果图不一样)
⚠️ 因为此读取方法已在 iOS 14 被标示 Deprecated!
⚠️ 因为此读取方法已在 iOS 14 被标示 Deprecated!
⚠️ 因为此读取方法已在 iOS 14 被标示 Deprecated!
"Use ASAuthorizationController to make an ASAuthorizationPasswordRequest (AuthenticationServices framework)"
此方法仅适用 iOS 8 ~ iOS 14,iOS 13 之后可改用同 Sign in with Apple 的 API — 「 AuthenticationServices 」
AuthenticationServices 读取方式
支援度 iOS ≥ 13
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import AuthenticationServices
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
//...
let request: ASAuthorizationPasswordRequest = ASAuthorizationPasswordProvider().createRequest()
let controller = ASAuthorizationController(authorizationRequests: [request])
controller.delegate = self
controller.performRequests()
//...
}
}
extension ViewController: ASAuthorizationControllerDelegate {
func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) {
if let credential = authorization.credential as? ASPasswordCredential {
// fill credential.user, credential.password to textfield
}
// else if as? ASAuthorizationAppleIDCredential... sign in with apple
}
func authorizationController(controller: ASAuthorizationController, didCompleteWithError error: Error) {
// alert error
}
}
效果图,可以看到新的做法在流程上、显示上都能跟 Sign in with Apple 整合得更好。
⚠️ 此登入无法取代 Sign in with Apple(两个是不同东西)。
写入帐号密码到「密码」
被 Deprecated 的只有读取的部分,新增、删除、编辑的部分都还是照旧能用。
新增、删除、编辑的部分使用 SecAddSharedWebCredential
进行操作。
1
2
3
4
5
6
7
8
9
SecAddSharedWebCredential(domain as CFString, account as CFString, password as CFString?) { (error) in
DispatchQueue.main.async {
guard error == nil else {
// alert error
return
}
// alert success
}
}
SecAddSharedWebCredential(fqdn, account, password, completionHandler)
fqdn 可随意指定要存入的 domain 不一定要在
webcredentials
中account 指定要新增、修改、删除的帐号
如果要删除资料则将 password 带入
nil
处理逻辑:
- account 存在&有带入 password = 修改 password
- account 存在&password 带入 nil = 从 domain 删除 account, password
- account 不存在&有带入 password = 新增 account, password 到 domain
⚠️ 另外也不是能让你在背景偷修改的,每次修改都会跳出提示框提示使用者,使用者按「更新密码」才会真的修改资料。
密码产生器
最后一个小功能,密码产生器。
使用 SecCreateSharedWebCredentialPassword()
进行操作。
1
let password = SecCreateSharedWebCredentialPassword() as String? ?? ""
产生器产生出来的 Password 由英文大小写及数字并使用「-」组成 (ex: Jpn-4t2-gaF-dYk)。
完整测试专案下载
美中不足
如果有使用第三方密码管理工具(EX: onepass、lastpass)的朋友可能会发现,如果是键盘的 Password AutoFill 能支援显示&输入,但是在 AuthenticationServices 或 SecRequestSharedWebCredential 当中都没有显示出来;不确定有没有办法达成这个需求。
结束
感谢大家阅读,也感谢 saiday 、街声让我知道有这个功能 XD。
还有 XCode ≥ 12.5 模拟器新增录影,并支援储存成 GIF 功能太好用啦!
在模拟器上按「Command」+「R」开始录影,按一下红点停止录影;在右下角滑出的预览图上按「右键」->「Save as Animated GIF」即可存成 GIF 然后直接贴到文章内!
有任何问题及指教欢迎 与我联络 。
本文首次发表于 Medium (点击查看原始版本),由 ZMediumToMarkdown 提供自动转换与同步技术。