Home iOS 跨平台帳號密碼整合加強登入體驗
Post
Cancel

iOS 跨平台帳號密碼整合加強登入體驗

iOS 跨平台帳號密碼整合,加強登入體驗

除 Sign in with Apple 也值得加入的功能

Photo by [Dan Nelson](https://unsplash.com/@danny144?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText){:target="_blank"}

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-associationgoogle.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 ➡️ 前往查看


This post is licensed under CC BY 4.0 by the author.

AVPlayer 實踐本地 Cache 功能大全

Universal Links 新鮮事