版本记录
版本号 | 时间 |
---|---|
V1.0 | 2019.06.18 星期二 |
前言
有关通讯录的框架有好几种,包括
AddressBook
、AddressBookUI
、Contacts
和ContactsUI
,这里,iOS9
以后AddressBook、AddressBookUI
就不推荐使用了,但是如果要支持ios8
以及以前的系统还是要用它们两个框架的。ios9以后系统推荐使用Contacts
和ContactsUI
,接下来的几篇我们就详细的解析一下这几个框架。感兴趣的可以看我写的上面几篇。
1. 通讯录相关框架详细解析(一)—— AddressBook框架基本概览
2. 通讯录相关框架详细解析(二)—— AddressBookUI框架基本概览
3. 通讯录相关框架详细解析(三)—— Contacts框架基本概览(一)
4. 通讯录相关框架详细解析(四)—— ContactsUI框架基本概览(一)
开始
首先看下写作环境
Swift 5, iOS 12, Xcode 10
在此iOS Contacts
框架教程中,了解如何从用户设备中选择,显示,保存和编辑联系人。
移动设备最重要的功能之一是为您想要与之通信的人存储联系信息。 无论是通过电话,消息传递还是共享非常重要的memes
,如果没有这些信息,您的设备将无法进行通信。 您可以使用Contacts
框架获取此信息。
作为应用程序开发人员,了解如何使用联系信息更好地将应用程序与用户设备集成非常重要。 在此Contacts
框架教程中,您将学习如何使用Contacts和ContactsUI框架。
通过Contacts
框架,您可以从应用程序中读取或修改用户的联系人。 这些是在Contacts
应用中显示的相同联系人。 它取代了旧的Address Book
框架。
在本教程中,您将学习在之前学习中使用的应用程序的修改版本。 您将能够选择,显示,保存和编辑存储在用户设备上的联系人。
打开已有的入门项目。 该应用程序有一些基本界面来显示默认联系人列表。 您将实现一些按钮,因此并非所有内容都在UI中运行。
构建并运行项目,您将看到已在应用程序中进行硬编码的著名联系人列表。
在您使用contacts
之前,您需要熟悉CNContact
,该类用于存储您的应用程序可能访问的所有联系人信息。 打开Friend.swift
并看一下。 Friend
是这个项目的一个类,它有一个属性contactValue
。
Showing Contacts Information
如果您在使用contacts
,您可能希望在某些时候显示此信息。 Apple提供了一个内置的视图控制器,可以显示CNContact
,只需要很少的工作。
打开FriendsViewController.swift
并在文件顶部添加此导入:
import ContactsUI
接下来,将此代码添加到tableView(_:didSelectRowAt :)
:
// 1
let friend = friendsList[indexPath.row]
let contact = friend.contactValue
// 2
let contactViewController = CNContactViewController(forUnknownContact: contact)
contactViewController.hidesBottomBarWhenPushed = true
contactViewController.allowsEditing = false
contactViewController.allowsActions = false
// 3
navigationController?.navigationBar.tintColor = .appBlue
navigationController?.pushViewController(contactViewController, animated: true)
下面进行详细分解
- 1) 你从
friend
那里得到了CNContact
值。 - 2) 您创建了一个
CNContactViewController
并对其进行了配置。 在这里,您关闭了编辑和操作(editing and actions)
。 如果您希望UI显示允许您与此人共享联系人或您的位置的按钮,则可以将allowsActions
设置为true
。 - 3)
CNContactViewController
具有浅色主题,与在Contacts.app
中查看联系人时的主题非常相似。 由于应用程序的主题,您需要在呈现contact controller
之前调整导航栏的色调,以便可以看到导航按钮。 颜色已在viewWillAppear(_ :)
中切换回来。
构建并运行并选择列表中的任一联系人。 现在,您将看到一个漂亮的视图控制器中显示的联系人,而您根本没有太多工作。
Picking Contacts
接下来,您可以使用联系人选择器(contact picker)
更多地利用ContactsUI
框架。 这是从用户设备中选择联系人并将数据导入应用程序的内置方式。
打开FriendsViewController.swift
并将以下代码添加到文件的底部:
//MARK: - CNContactPickerDelegate
extension FriendsViewController: CNContactPickerDelegate {
func contactPicker(_ picker: CNContactPickerViewController,
didSelect contacts: [CNContact]) {
let newFriends = contacts.compactMap { Friend(contact: $0) }
for friend in newFriends {
if !friendsList.contains(friend) {
friendsList.append(friend)
}
}
tableView.reloadData()
}
}
在这里,您确保从CNContactPickerViewController
中选择的联系人已正确添加到列表中,但前提是它们之前未添加。
最后,将以下实现添加到addFriends(sender :)
:
// 1
let contactPicker = CNContactPickerViewController()
contactPicker.delegate = self
// 2
contactPicker.predicateForEnablingContact = NSPredicate(
format: "emailAddresses.@count > 0")
present(contactPicker, animated: true, completion: nil)
以下是您添加内容的快速细分:
- 1) 您创建了一个联系人选择器并设置了代理。
- 2) 您在联系人选择器上设置谓词
(predicate)
。 您可以使用谓词来过滤符合您选择的特定条件的联系人。 在这种情况下,您可以确保要选择的联系人至少有一个电子邮件地址。
构建并运行,然后从右上角选择添加按钮。
如果您在模拟器中运行,您将看到David Taylor
的默认联系人列表变灰。 这是因为他的联系人没有电子邮件地址。
从列表中选择其中一个联系人,然后选择Done
。 您应该看到联系人在列表中,其中包含默认联系人。
Setting Up Contacts Permissions
到目前为止,您无需获得许可即可访问用户的联系人数据。 你可以这样做,因为Apple称之为out-of-process pickers。 选择器在您的应用程序进程外运行,您获得的唯一信息是用户选择的数据。
对于后续步骤,您将直接存储的访问联系人。 您需要适当的权限才能执行此操作。
首先,打开Info.plist
并选择属性列表中任何项旁边的add
按钮。 在新添加的项目中,查找或键入:
Privacy - Contacts Usage Description
在value
字段中,添加以下描述:
Access is needed to save your RWConnect friends information to your Contacts list.
系统将在显示要求许可的alert
时向用户显示此属性的值。
注意:请务必正确解释您需要该权限的原因,因为模糊目的字符串可能导致应用审核中的拒绝。
接下来,打开AppDelegate.swift
并将Contacts
的导入添加到文件顶部:
import Contacts
最后,在它返回之前将以下代码添加到application(_:didFinishLaunchingWithOptions:)
:
CNContactStore().requestAccess(for: .contacts) { (access, error) in
print("Access: \(access)")
}
此代码将触发系统要求用户访问Contacts
的权限。
构建并运行项目,您将看到Info.plist
中添加了文本值的权限alert
。 一定要选择OK
。
Editing Contacts
在最后一节中,您将编辑联系人并将其保存回用户的设备。 到目前为止,您一直在使用ContactsUI
框架提供的内置UI。 现在,您将使用自定义UI编辑或向联系人添加电话号码,并将其保存回设备的联系人记录。
为此,您将从设备中获取联系人并检查是否已存在电话号码,然后将其显示在EditFriendTableViewController
中。
在FriendsViewController.swift
中,添加以下代码到 prepare(for:sender:)
:
if segue.identifier == "EditFriendSegue",
// 1
let cell = sender as? FriendCell,
let indexPath = tableView.indexPath(for: cell),
let editViewController = segue.destination as? EditFriendTableViewController {
let friend = friendsList[indexPath.row]
// 2
let store = CNContactStore()
// 3
let predicate = CNContact.predicateForContacts(matchingEmailAddress: friend.workEmail)
// 4
let keys = [CNContactPhoneNumbersKey as CNKeyDescriptor]
// 5
if let contacts = try? store.unifiedContacts(matching: predicate, keysToFetch: keys),
let contact = contacts.first,
let contactPhone = contact.phoneNumbers.first {
// 6
friend.storedContact = contact.mutableCopy() as? CNMutableContact
friend.phoneNumberField = contactPhone
friend.identifier = contact.identifier
}
editViewController.friend = friend
}
这是你添加的内容:
- 1) 这将从
table view
中选择FriendCell
。 - 2) 您创建
CNContactStore
。这是允许您通过fetch and save requests
来读取和写入联系人的类。 - 3) 您可以使用
CNContact
上提供的类方法创建一个谓词,该谓词将过滤朋友的工作电子邮件。 - 4) 这将创建您要从商店中获取的键数组。由于您要编辑电话号码,因此这是您要添加的唯一键。
- 5) 接下来,您在商店上执行提取。您可以在此处看到传递给fetch的
predicate
和keys
。 - 6) 最后,如果联系人与谓词匹配,则使用添加的电话号码创建可变联系人。如果要编辑联系人信息,则需要使用
CNMutableContact
实例。您还会注意到标识符已添加到联系人中 - 您稍后将使用此标识符。
建立并运行。在任何联系人上选择信息附件,i
按钮,然后查看EditFriendTableViewController
现在已填充联系人信息。
您可能会注意到电话号码区域仍为空。 那是因为没有一个默认联系人有电话号码。
将设备的其中一个联系人添加到好友列表,然后选择信息info
附件。 您可以看到也填充了电话号码。
在最后一步中,您将保存联系人信息到设备。 打开EditFriendTableViewController.swift
并将以下内容添加到save(_ :)
的末尾:
let store = CNContactStore()
guard
let friend = friend,
let phoneNumberText = phoneTextField.text
else { return }
let phoneNumberValue = CNPhoneNumber(stringValue: phoneNumberText)
let saveRequest = CNSaveRequest()
在这里,您创建了一个CNContactStore
并确保您拥有可以保存到电话号码的文本。 使用联系人时,无法将String
类型保存为电话号码,因此您需要CNPhoneNumber
类型。
最后,由于您要保存信息,因此需要CNSaveRequest
。 您将决定联系人是否需要使用此请求对象添加或更新。
接下来,在刚刚添加的内容之后添加以下内容:
if let storedContact = friend.storedContact,
let phoneNumberToEdit = storedContact.phoneNumbers.first(
where: { $0 == friend.phoneNumberField }
),
let index = storedContact.phoneNumbers.firstIndex(of: phoneNumberToEdit) {
// 1
let newPhoneNumberField = phoneNumberToEdit.settingValue(phoneNumberValue)
storedContact.phoneNumbers.remove(at: index)
storedContact.phoneNumbers.insert(newPhoneNumberField, at: index)
friend.phoneNumberField = newPhoneNumberField
// 2
saveRequest.update(storedContact)
friend.storedContact = nil
} else if let unsavedContact = friend.contactValue.mutableCopy() as? CNMutableContact {
// 3
let phoneNumberField = CNLabeledValue(label: CNLabelPhoneNumberMain,
value: phoneNumberValue)
unsavedContact.phoneNumbers = [phoneNumberField]
friend.phoneNumberField = phoneNumberField
// 4
saveRequest.add(unsavedContact, toContainerWithIdentifier: nil)
}
它可能看起来很多,但下面进行细分:
- 1) 在
if
条件下,您正在检查您是否正在使用已保存到设备的联系人。使用联系人时遇到的一个问题是您无法直接更新电话号码字段 - 您必须更换它。phoneNumberToEdit
是最初显示的旧电话号码,并使用用户编辑的新电话号码进行更新,然后换出联系人。 - 2) 由于此联系人已经存在并且只需要更新,因此您将在
CNSaveRequest
上将其传递给update(_ :)
。这是可能的,因为在前面的步骤中设置了identifier
。如果联系人尚不存在,尝试保存会抛出错误。 - 3)
else if
条件适用于设备上尚不存在的默认联系人。由于他们还没有电话号码,您需要从头开始创建新的电话号码。您可以使用CNLabeledValue
执行此操作。您可以从不同电话号码标签的列表中进行选择,但在这种情况下,您将保存电话号码作为主要电话号码。 - 4) 与更新联系人的情况一样,您需要告知保存请求您要将此联系人添加到设备。
你几乎完成!最后一步是执行保存。在save(_ :)
结束时添加最后一段代码:
do {
try store.execute(saveRequest)
let controller = UIAlertController(title: "Success",
message: nil,
preferredStyle: .alert)
controller.addAction(UIAlertAction(title: "OK", style: .default))
present(controller, animated: true)
setup()
} catch {
print(error)
}
在这里,您尝试在store
上执行保存请求。 如果有效,您将看到成功消息。
注意:
CNContactStore
上的方法是同步的并访问文件系统,因此在生产代码中,您应该在后台线程上实际运行它们。
构建并运行和编辑默认联系人以获取电话号码。 保存后,在模拟器或设备上打开Contacts.app
,找到您保存的联系人。 您将看到应用程序中始终显示的默认信息以及您添加的电话号码。
接下来,在应用程序中,从设备添加联系人。 编辑电话号码并保存。 返回Contacts.app
,找到联系人以查看您保存的更新的电话号码。
通过使用Contacts
框架,您可以简化需要联系信息的任务或增强联系人体验,而无需强制用户维护其联系人的单独副本。 如果您想了解更多信息,可以阅读Apple文档中关于Contacts framework和ContactsUI上的相关内容。
还有关于Apple的Apps Privacy的精彩视频。
后记
本篇主要讲述了
Contacts
和ContactsUI
框架,感兴趣的给个赞或者关注~~~