最近因为有需求, 调查了一下这方面的东西,所以整理一下 以便未来参考吧

首先 iOS 的密码填充从iOS 11 推出后到 13,基本完善了,后面密码方面再更新的都是用 "Apple 登录", 第三方密码管理器之类的的东西了


苹果将这个键盘上方的位置称为 QuickType bar, 这里除了密码推荐外还有可能推荐地址、联系人信息、验证码. (当然需要开发者设置UITextContentType为username, password, oneTimeCode, fullStreetAddress, email, telephoneNumber等)
验证码的显示是由系统自动解析短信获得的,会在这个区域显示三分钟,或用户点击填充后消失

这次主要关注密码填充相关, 要在 App 中实现这样的一个自动推荐填充密码的功能我们可以把整个功能分为三步:

  1. 建议新密码 (如果有注册流程)

  2. 保存密码

  3. 密码推荐

但这些只要我们配置好了输入框的属性,那么我们就无需关注实现的细节

与网站关联的配置

但实现这些功能有一个前提, 就是我们需要将 App 与网站进行关联, 与 Android可以以应用包名作为标示存储账号密码不同, iOS 的密码保存必须在有关联网站的情况下才可以进行, 以 Nintendo switch online 这个据说 ns 内置的App是 fenrir 开发 ,但手机版 App 我不知道是谁开发的应用为例, 它没有一个对应的网页, 所以使用了 accounts.nintendo.com 作为关联域(Associated Domains Entitlement) 来保存账号密码

我们要实现密码自动填充相关的功能也需要这样做,简单的说需要:

  • 添加相关域名

在 Xcode 的 Project Navigator 中,选择你的应用目标,进入 "Signing & Capabilities" 选项卡,添加 "Associated Domains" 的Capability。然后添加相关域名, 不要包含路径和query或尾部斜线"/"

  • 将关联域文件添加到网站上
    要将关联域文件添加到网站,需要创建一个名为 apple-app-site-association 的文件(无扩展名)并将其放置在网站的 . well-known 目录中. url 大概是这样的: https://<fully qualified domain>/.well-known/apple-app-site-association

通用链接, App Clip 相关的功能也会用到它

关联域文件的例子:

{
  "applinks": {
      "details": [
           {
             "appIDs": [ "ABCDE12345.com.example.app", "ABCDE12345.com.example.app2" ],
             "components": [
               {
                  "#": "no_universal_links",
                  "exclude": true,
                  "comment": "Matches any URL with a fragment that equals no_universal_links and instructs the system not to open it as a universal link."
               },
               {
                  "/": "/buy/*",
                  "comment": "Matches any URL with a path that starts with /buy/."
               },
               {
                  "/": "/help/website/*",
                  "exclude": true,
                  "comment": "Matches any URL with a path that starts with /help/website/ and instructs the system not to open it as a universal link."
               },
               {
                  "/": "/help/*",
                  "?": { "articleNumber": "????" },
                  "comment": "Matches any URL with a path that starts with /help/ and that has a query item with name 'articleNumber' and a value of exactly four characters."
               }
             ]
           }
       ]
   },
   "webcredentials": {
      "apps": [ "ABCDE12345.com.example.app" ]
   },


    "appclips": {
        "apps": ["ABCED12345.com.example.MyApp.Clip"]
    }
}

另外如果网站使用多个子域(如 example.com 、 www.example.com 和 support.example.com ),则每个子域都需要在 Associated Domains Entitlement 中有自己的条目,并且每个子域都必须有自己的 apple-app-site-association 文件

  • 系统验证并开启相关功能

以上两步完成后,当 App 安装到设备上时,系统就会尝试下载解析该apple-app-site-association 文件,成功关联后密码填充相关的功能就可以用了.

另外以前是 APP 直接访问网站进行验证,而现在是苹果的 CDN 来进行这个验证,在开发App时,如果公共互联网无法访问网络服务器,\可以使用备用模式功能绕过 CDN,直接连接到专用域。可以通过在关联域的权限中添加查询字符串来启用备用模式: <service>:<fully qualified domain>?mode=<alternate mode>

Q&A

  • 密码填充的功能的出现时机

当用户在设备上至少存储过一个密码(不限定 app 或网站,也可能通过 iCloud 同步到设备上), 并在系统设置中打开了 Keychain AutoFill (系统设置→密码→密码选项), 那么 QuickType bar (也就是键盘上的密码区域) 就会出现, 并且可以通过钥匙图标进一步访问设备上存储的所有密码(不限 app)来选择填充

关闭掉Keychain AutoFill的话,无论怎么样都不会出现密码填充推荐和钥匙按钮了

另外在密码输入框时,只能使用系统提供的输入法, 不可以切换到第三方输入法, 因此即使用户使用第三方输入法也不会破坏该功能

  • 没有在APP内保存过账号密码时会出现吗

就像之前说的,如果没有相关的密码保存,那么 QuickType bar 不会显示具体的账户信息,而是提供一个钥匙按钮,用户可以进入选择他认为合适的密码填充进 App 里

比如用户在各种网站都习惯用同一套密码,或者他手动存储了一套密码时都可以这样选择他认为合适的密码来填充

  • 在网页端保存过的账号密码,APP是否可以直接选择使用

当 APP 有网页版时,只要我们按照上面所说的配置好关联域(可以配置多个网站)那么就会出现推荐来直接选择

以 Instagram ( Facebook旗下 App) 为例, 它可以填充来自用户在 Instagram.com 和 Facebook.com 网页中保存的密码

  • 使用第三方密码管理工具会不会影响该功能

由于这种自动填充都是通过钥匙串 API 进行互动的, 我们不需要特别在意用户可能使用了什么第三方工具, 比如上面Instagram的例子中密码就是由 Chrome 的 Google 密码管理工具提供的账户密码, 在点击密码选择时也和系统原生操作一样.

  • 密码填充必须要验证吗?

必须使用 face id 或 touch id 进行验证

  • 存储需要用 face id 等验证吗?

不需要,确认需要保存就可以了

  • flutter 中怎么实现呢

具体请参考 autofillHints property  只要完成了上面原生也需要配置的东西,那么直接为输入框设置一些密码相关的属性就可以了

另外拿iOS-033测试机做实验时发现,最开始在各种 App 内均不会出现密码填充的 QuickType bar ,但关闭设置中的密码填充功能, 重启设备后再打开后成功出现了(果然重启解决一切,如果不行就重装 x). 因此如果以后测试时遇到了问题,不妨这样操作试试看

参考:
API Collection Password AutoFill

About the Password AutoFill workflow

Associated Domains Entitlement

Supporting associated domains