大多数浏览器和
Developer App 均支持流媒体播放。
-
了解 Contact Access 按钮
了解新的“通讯录”授权模式,以及如何在你的 App 中改进对“通讯录”的访问权限。探索如何将 Contact Access 按钮整合到 App 中,以按需共享额外的联系人信息,并为“通讯录”授权提供更简单的路径。我们还将介绍一些“通讯录”安全功能,以及一种在该按钮不适合你的 App 时可以使用的替代 API。
章节
- 0:00 - Introduction
- 0:36 - Limited Access
- 2:56 - Contact Access Button
- 8:28 - Accessing contacts
- 13:34 - Which access method to use
资源
-
下载
大家好 我是 Ada 在本视频中 我将简单介绍 ContactAccessButton 以及如何在 App 中使用它 首先我将简要介绍 iOS 18 中的 “有限访问权限”功能 然后我将介绍新的 ContactAccessButton API 以及如何使用它在你的 App 中 打造出色的“通讯录”体验 最后我将讨论 访问通讯录的其他方式 和它们在有限访问权限下的 工作方式
在 iOS 18 中 通讯录授权 现在提供一个选项 可以仅共享通讯录数据库的一部分 这称为“有限访问权限” 通讯录授权提示现在分为两个阶段 第一个提醒询问 是否向 App 共享通讯录 如果轻点“继续” 会显示第二个提示 其中提供共享通讯录的 两个不同选项 可以选择一组联系人进行共享 或者 App 将获得 通讯录的完整访问权限 提示会强调这不是最终选择 用户可以在日后 添加要共享的联系人
在选择了所需的一组联系人之后 将出现一个确认屏幕 其中显示所选的联系人 这个新的授权流程显著改善了 通讯录隐私保护 使用户能够 透明地了解并控制要共享的联系人
推出这项新功能后 现在有 4 个授权级别 完整访问权限允许 App 读取任何联系人 还能够修改联系人或新建联系人
有限访问权限 允许 App 读取 用户授权它访问的联系人 与完整访问权限一样 App 可以修改或创建联系人
App 一开始总是 具有“未确定”授权状态 如果你尝试访问联系人存储 授权提示将模态化显示
如果 App 获得授权 访问尝试就会成功
最后 如果 App 的授权级别为“拒绝” 它将无法读取或写入联系人数据
为了在访问权限有限的情况下 打造出色的体验 iOS 18 添加了两个新的 API 用于授权 App 访问更多联系人 借助 Contact Access 选择器 用户可以轻松更改 App 有权访问的联系人 而无需离开 App
Contact Access 按钮 是一个强大的全新方式 用于直接在 App 中管理 联系人访问权限 这个按钮会嵌入到你的 UI 中 而不是显示为全屏选择器 用户只需轻点一下 即可授予新联系人的访问权限 现在你已经了解了 访问通讯录的基本知识 我很高兴能为你介绍 App 处理 有限访问权限的最佳方式 Contact Access 按钮! ContactAccessButton 是一种简化的方式 可使 App 在 App 中获得 更多联系人的访问权限
当你将这个按钮添加到 App 的 联系人搜索流程中时 它会显示你的 App 还没有访问权限的 联系人的搜索结果 它的设计思路是 无缝融入你的 App
当按钮有唯一匹配时 只需轻点一下按钮 便可向 App 授予匹配联系人的访问权限 它在你的 App 中提供 功能全面的联系人选择器体验 而无需完整的访问权限
这种有限访问权限的 渐进式方法意味着 App 将精确获得它需要的 联系人的访问权限 且恰好在它需要这个 访问权限的地方 这会让用户更放心地 向你的 App 共享联系人信息
请求授权的最佳时机 是某个交互需要访问权限的时候 如果在需要数据的时候请求 那么授予访问权限后 你的 App 将提供什么功能 就十分显而易见
Contact Access 按钮 就是围绕着这一原则设计的 当你使用它时 你的 App 围绕着 这样的工作流程 即在有明确需求共享每个联系人时 请求访问权限
用户不需要猜测 你的 App 将需要哪些联系人 这个按钮可以让用户 在具体的情境中做出决定 此时用户确切地知道 要共享的联系人
Contact Access 按钮 将这个理念更推进一步 它可以在 App 的授权级别 仍为“未确定”状态时显示
如果在你的 App 获得授权之前 轻点按钮 它会自动显示一个简化的提示 来请求有限访问权限 由于这在轻点联系人搜索结果 之后立即发生 用户很容易理解为什么 你的 App 需要访问权限 这样你的 App 就更有可能 获得访问权限
这个示例展示如何在 App 中 使用按钮 这个简单的视图用于 在 App 中显示联系人搜索的结果
这个视图具有一个绑定 绑定到在 App 的搜索文本栏中 输入的文本
它会跟踪 App 的授权状态
首先我会展示 App 能够从 它自己的数据存储中检索的结果 我使用一个简单的 ForEach 来实现
在 App 自己的搜索结果之后 我会有条件地展示 Contact Access 按钮 前提是 App 具有 limited 或 notDetermined 授权状态
在初始化按钮时 我传入 搜索栏中输入的文本
最后 在回调代码块中 我将收到 联系人标识符字符串的数组 此时 我可以检索联系人详细信息 并关闭搜索 UI
这个按钮的设计思路是 针对 App 的外观量身定制 使用的是标准的 SwiftUI 修饰符
font 修饰符控制主文本 以及跟随的操作标签的外观
foregroundStyle 修饰符 更改主文本的颜色
操作标签使用 App 的着色颜色
最后还有几个按钮专用的修饰符 当有单个匹配时 按钮可以显示 匹配联系人的部分信息 可用 contactAccessButtonCaption 修饰符来指定
联系人照片的大小也可以自定义 只需使用 contactAccessButtonStyle 修饰符
联系人按钮是强大且便捷的方式 来让 App 获得更多访问权限 并支持强大的隐私保护 按钮可以在 App 获得敏感信息 的访问权限之前显示信息 所以按钮的内容保持私密 但在 App 中可见
此外 按钮只响应已验证的事件
最后 只有在按钮内容清晰可辨 且不被遮挡的情况下 轻点按钮才会授予访问权限 这可确保用户始终清楚地知道 轻点按钮会执行哪些操作
按钮必须清晰可辨且不被遮挡 否则按钮将不会向 App 授予 更多联系人的访问权限
首先是配置正确的按钮示例 前景与背景之间的对比很明显 留出足够的空间来显示 整个按钮清晰可见 这满足了按钮易读性的所有要求 下面是配置不正确的按钮示例 文本与背景之间的对比度非常低 文本为浅灰色 背景为白色
按钮的一部分被剪切 导致按钮被遮挡
轻点这个按钮将不会授予 联系人访问权限
请始终确保 Contact Access 按钮清晰可辨 未被遮挡且有足够的空间来显示
除了按钮 通讯录框架还有另外 3 种方式 可让你访问联系人数据 我将介绍它们的工作方式 以及在使用它们时 “有限访问权限”意味着什么
CNContactStore 是 访问联系人数据的主要方式 它可以获取联系人 和创建新的联系人条目
当你的 App 尝试 访问联系人数据时 CNContactStore 会自动显示授权提示
使用 CNContactStore 检查 App 的授权级别 并根据授权级别显示相应的 UI
只有当 App 获得授权时 尝试读取或写入联系人数据 才会成功
它还会在联系人数据发生变化时 发送通知 并可用于确定发生了什么变化
App 具有有限访问权限时 联系人存储将仅提供 用户向 App 共享的联系人条目 对于新的 .limited 枚举 case 通过检查授权状态来确定 授予的是完整还是部分访问权限 .limited 状态用于 确定要显示的 UI 这有助于有选择地使用 针对 .limited 授权而设计的 新的 Contacts API 如 ContactAccessButton
最后 CNContactStore 是 使用 ContactAccessButton 时 不可或缺的部分 它会返回联系人标识符数组 通过 CNContactStore 使用这些标识符来检索联系人数据 我将展示具体实现过程的示例
这个函数接受 联系人标识符字符串数组 并返回这些标识符代表的 CNContact 为了避免遮挡主角 我在 await 任务中 执行 fetch
在这个任务中 我首先创建一个 CNContactFetchRequest 在其中我列出要获取的 联系人字段对应的键 在这个示例中 我只获取显示联系人姓名 所需的字段
为了按标识符获取联系人 我使用 CNContact predicateForContacts(withIdentifiers:)
之后 使用 CNContactStore 的 enumerateContacts(with:) 并将结果收集到数组中 下一个访问联系人数据的方法是使用 CNContactPickerViewController 这个视图控制器展示 用于从联系人数据库选择 一个或多个联系人的系统 UI
选择联系人后 你的 App 会收到所选联系人的 一次性快照 无论 App 具有什么授权级别 这个视图控制器都会起作用 而且始终显示整个联系人数据库
用户交互给出隐式许可 当选择器中选择了 一个或多个联系人时 App 会收到联系人数据
CNContactPickerViewController 最适合用于 为一次性任务 请求联系人信息的情况 例如选择电子邮件地址或电话号码 因为联系人只会暂时与 App 共享
iOS 18 有一个新的选择器 称为 contactAccessPicker 它显示模态表单 在其中可以更改 App 的有限访问权限联系人 对于批量或非即时的应用场景 可以使用 contactAccessPicker 访问更多联系人 例如 社交媒体 App 可能希望提供 共享更多联系人的功能 以进行好友匹配
contactAccessPicker 会返回 新允许的联系人的标识符
这不同于 CNContactPickerViewController contactAccessPicker 通过 CNContactStore 来管理 App 能够访问的联系人 CNContactPickerViewController 提供 联系人数据一次性快照的访问权限
这个示例说明了它的使用方法 在示例中 我有一个简单的按钮 来切换 State bool 然后我使用 contactAccessPicker 方法 使按钮在 bool 为 true 时 显示选择器
最后 在回调代码块中 我获取 App 刚刚获得 访问权限的联系人
和 ContactAccessButton 一样 这个回调代码块收到 联系人标识符字符串数组 因此我通过完全相同的方式 获取联系人 请注意 回调代码块仅报告 新获得访问权限的联系人 我刚才介绍过的所有示例 都可以在与本视频相关的 示例 App 中找到 还附有说明 API 使用方式的注释
访问通讯录有四种不同的方式 授权级别对每种方式的 影响是不同的 这里说明各个方法应该 在什么情况下使用
CNContactPickerViewController 在所有授权级别都适用 允许 App 获得视图控制器中 选择的联系人的一次性访问权限 始终如此 CNContactStore 是联系人数据的 主要入口 需要获得授权 在极少数情况下 当你的 App 获得完整授权时 它能够读取或写入任何联系人数据 如果你的 App 获得有限的授权 它只能访问获得许可的那些联系人
当你的 App 获得未确定授权 CNContactStore 会在需要时 显示授权提示
如果你的 App 被拒绝授权 那么它无权访问联系人数据 ContactAccessButton 用于 在 App 获得有限访问权限时 访问更多联系人 轻点按钮时 使用 CNContactStore 检索联系人信息 这个按钮还可以在 App 获得授权之前使用 UI 中的 ContactAccessButton 可以在 App 获得有限授权时 提供最佳体验
contactAccessPicker 用于管理 App 的有限访问权限 应当仅在 App 获得 有限授权时使用
现在你已经了解了 所有通讯录授权级别 和访问方法
那么 接下来该怎么做? 在 iOS18 上运行你的 App 并测试 它在有限访问权限下的运行情况 使用 ContactAccessButton 进行通讯录访问权限管理 在 App 的 UI 中 并且在需要特定联系人时显示
决定哪种联系人访问方式最适合 让用户在你的 App 中 共享联系人信息
谢谢观看!
-
-
5:15 - Using ContactAccessButton
// Using ContactAccessButton @Binding var searchText: String @State var authorizationStatus: CNAuthorizationStatus = .notDetermined var body: some View { List { ForEach(searchResults(for: searchText)) { person in ResultRow(person) } if authorizationStatus == .limited || authorizationStatus == .notDetermined { ContactAccessButton(queryString: searchText) { identifiers in let contacts = await fetchContacts(withIdentifiers: identifiers) dismissSearch(withResult: contacts) } } } }
-
6:10 - Appearance options
ContactAccessButton(queryString: searchText) .font(.system(weight: .bold)) .foregroundStyle(.gray) .tint(.green) .contactAccessButtonCaption(.phone) .contactAccessButtonStyle(ContactAccessButton.Style(imageWidth: 30))
-
10:11 - Fetching contacts with CNContactStore
// Fetching contacts with CNContactStore func fetchContacts(withIdentifiers identifiers: [String]) async -> [CNContact] { return await Task { let keys = [CNContactFormatter.descriptorForRequiredKeys(for: .fullName)] let fetchRequest = CNContactFetchRequest(keysToFetch: keys) fetchRequest.predicate = CNContact.predicateForContacts(withIdentifiers: identifiers) var contacts: [CNContact] = [] do { try CNContactStore().enumerateContacts(with: fetchRequest) { contact, _ in contacts.append(contact) } } catch { // ... } return contacts }.value }
-
12:47 - Using contactAccessPicker
// Using contactAccessPicker @State private var isPresented = false var body: some View { Button("Show picker") { isPresented.toggle() }.contactAccessPicker(isPresented: $isPresented) { identifiers in let contacts = await fetchContacts(withIdentifiers: identifiers) // use the new contacts! } }
-
-
正在查找特定内容?在上方输入一个主题,就能直接跳转到相应的精彩内容。
提交你查询的内容时出现错误。请检查互联网连接,然后再试一次。