需求中不少会出现选择联系人信息的情况,有些需要自定义UI,有些不需要。直接调用系统的不需要授权,自定义UI只获取数据的需要用户授权。
#import <ContactsUI/ContactsUI.h> //有UI效果
#import <Contacts/Contacts.h> //无UI效果,只拿到数据,UI可以自定义
<CNContactPickerDelegate> //遵循协议
import Contacts
import ContactsUI
CNContactPickerDelegate
ContactsUI (有UI效果,无需自定义)
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
CNContactPickerViewController *cncpVC = [[CNContactPickerViewController alloc]init];
cncpVC.delegate = self;
[self presentViewController:cncpVC animated:YES completion:nil];
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let cpvc = CNContactPickerViewController()
cpvc.delegate = self
self.present(cpvc, animated: true, completion: nil)
}
代理方法根据需求二选一实现
#pragma mark - CNContactPickerDelegate
/**
选择单个联系人
@param picker 通讯录列表
@param contact 联系人对象
*/
-(void)contactPicker:(CNContactPickerViewController *)picker didSelectContact:(CNContact *)contact
{
NSLog(@"%@ %@",contact.givenName,contact.familyName);
for (CNLabeledValue *labelValue in contact.phoneNumbers) {
//contact.phoneNumbers联系人下的所有电话号码
NSString *phoneLabel = labelValue.label;
CNPhoneNumber *phoneNumer = labelValue.value;
NSString *phoneValue = phoneNumer.stringValue;
NSLog(@"%@ %@", phoneLabel, phoneValue);
}
}
/**
选中某一联系人的某一属性
@param picker 通讯录列表
@param contactProperty 联系人属性
*/
-(void)contactPicker:(CNContactPickerViewController *)picker didSelectContactProperty:(CNContactProperty *)contactProperty
{
NSLog(@"contact == %@\nkey == %@\nvalue == %@\nidentifier == %@\nlabel == %@",contactProperty.contact,contactProperty.key,contactProperty.value,contactProperty.identifier,contactProperty.label);
if ([contactProperty.key isEqualToString:@"phoneNumbers"]) {
for (CNLabeledValue *labelValue in contactProperty.contact.phoneNumbers) {
if ([labelValue.identifier isEqualToString:contactProperty.identifier]) {
CNPhoneNumber *phoneNumber = labelValue.value;
NSString *phoneStr = phoneNumber.stringValue;
NSLog(@"%@",phoneStr);
break;
}
}
}
}
/**
点击取消
@param picker 通讯录列表
*/
-(void)contactPickerDidCancel:(CNContactPickerViewController *)picker
{
NSLog(@"click cancel");
}
func contactPicker(_ picker: CNContactPickerViewController, didSelect contactProperty: CNContactProperty) {
print(contactProperty.contact.familyName + contactProperty.contact.givenName)
if contactProperty.key == "phoneNumbers" {
for labelVale in contactProperty.contact.phoneNumbers {
if contactProperty.identifier == labelVale.identifier {
let phoneStr = labelVale.value.stringValue
print(phoneStr)
}
}
}
}
点选属性时打印结果
contact == <CNContact: 0x7f8ebb80d510: identifier=9E55CCA2-E951-4DD7-AC18-86C2243BAA44, givenName=John, familyName=Appleseed, organizationName=, phoneNumbers=(
"<CNLabeledValue: 0x608000264140: identifier=8B15D69B-EEE8-4FAC-ACB9-041BEC74B880, label=_$!<Mobile>!$_, value=<CNPhoneNumber: 0x60800002ac60: countryCode=us, digits=8885555512>>",
"<CNLabeledValue: 0x6080002641c0: identifier=7D2CD244-2CB3-4778-AC37-967B5837BC84, label=_$!<Home>!$_, value=<CNPhoneNumber: 0x60800002ace0: countryCode=us, digits=8885551212>>"
), emailAddresses=(
"<CNLabeledValue: 0x6080002636c0: identifier=005253A8-BA89-4E3D-B2A3-C9C1B051A5D6, label=_$!<Work>!$_, [value=John-Appleseed@mac.com](mailto:value=John-Appleseed@mac.com)>"
), postalAddresses=(
"<CNLabeledValue: 0x608000264380: identifier=B8BACE69-C9A4-4EEC-979B-197B0F3AD29A, label=_$!<Work>!$_, value=<CNPostalAddress: 0x608000289ce0: street=3494 Kuhl Avenue, subLocality=, city=Atlanta, subAdministrativeArea=, state=GA, postalCode=30303, country=USA, countryCode=ca>>",
"<CNLabeledValue: 0x608000264400: identifier=4C5D91E4-3313-4154-B5E4-A4448F0E4AD6, label=_$!<Home>!$_, value=<CNPostalAddress: 0x608000289d30: street=1234 Laurel Street, subLocality=, city=Atlanta, subAdministrativeArea=, state=GA, postalCode=30303, country=USA, countryCode=us>>"
)>
key == phoneNumbers
value == <CNPhoneNumber: 0x60800002ace0: countryCode=us, digits=8885551212>
identifier == 7D2CD244-2CB3-4778-AC37-967B5837BC84
label == _$!<Home>!$_
Contacts(无UI效果,需自定义)
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self initData];
[self createCustomUI];
}
-(void)initData
{
self.dataArray = [[NSMutableArray alloc]init];
[self registAuthorize];
}
-(void)createCustomUI
{
self.tableView = [[UITableView alloc]initWithFrame:self.view.bounds];
self.tableView.delegate = self;
self.tableView.dataSource = self;
[self.view addSubview:_tableView];
}
#pragma mark - 请求授权
-(void)registAuthorize
{
CNAuthorizationStatus authorizationStatus = [CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts];
if (authorizationStatus == CNAuthorizationStatusNotDetermined) {
//用户还没有决定是否授权
CNContactStore *contactStore = [[CNContactStore alloc] init];
[contactStore requestAccessForEntityType:CNEntityTypeContacts completionHandler:^(BOOL granted, NSError * _Nullable error) {
if (granted) {
NSLog(@"授权成功!");
[self createCustomContact];
} else {
NSLog(@"授权失败, error=%@", error);
}
}];
}else if (authorizationStatus == CNAuthorizationStatusAuthorized){
//用户明确同意
[self createCustomContact];
}else{
//用户明确拒绝或者程序中阻止了通讯录,可跳转通讯录手动打开
}
}
#pragma mark - 获取数据
-(void)createCustomContact
{
CNContactStore *contactStore = [[CNContactStore alloc]init];
NSArray *keys = @[CNContactGivenNameKey, CNContactFamilyNameKey, CNContactPhoneNumbersKey];
CNContactFetchRequest *request = [[CNContactFetchRequest alloc]initWithKeysToFetch:keys];
__block int index = 1;
[contactStore enumerateContactsWithFetchRequest:request error:nil usingBlock:^(CNContact * _Nonnull contact, BOOL * _Nonnull stop) {
[self.dataArray addObject:contact];
NSLog(@"%@ %@",contact.givenName,contact.familyName);
for (CNLabeledValue *labelValue in contact.phoneNumbers) {
NSString *phoneLabel = labelValue.label;
CNPhoneNumber *phoneNumer = labelValue.value;
NSString *phoneValue = phoneNumer.stringValue;
NSLog(@"%@ %@", phoneLabel, phoneValue);
}
NSLog(@"---------------------------------%d",index);
index += 1;
//回到主线程刷新UI
dispatch_async(dispatch_get_main_queue(), ^{
[_tableView reloadData];
});
}];
}
#pragma tableViewDelegate
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return _dataArray.count;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cellID"];
if (!cell) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"cellID"];
}
if (_dataArray.count > 0) {
CNContact *contact = _dataArray[indexPath.row];
cell.textLabel.text = [NSString stringWithFormat:@"%@%@",contact.familyName,contact.givenName];
CNLabeledValue *labelValue = [contact.phoneNumbers firstObject];
CNPhoneNumber *phoneNum = labelValue.value;
cell.detailTextLabel.text = [NSString stringWithFormat:@"%@",phoneNum.stringValue];
}
return cell;
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
initData()
createLayout()
}
func initData() -> Void {
registAuthorize()
}
func registAuthorize() -> Void {
let authorizeState = CNContactStore.authorizationStatus(for: .contacts)
if authorizeState == .notDetermined {
//用户还未决定授权
let contactStore = CNContactStore.init()
contactStore.requestAccess(for: .contacts, completionHandler: { (granted: Bool, error: Error?) in
if granted {
print("授权成功")
self.createCustomContactData()
}else{
print("授权失败")
}
})
}else if authorizeState == .authorized {
//用户确认授权
createCustomContactData()
}else{
//用户拒绝或者有程序阻止了通讯录调起
}
}
func createCustomContactData() -> Void {
let contactStore = CNContactStore.init()
let keys = [CNContactFamilyNameKey, CNContactGivenNameKey, CNContactPhoneNumbersKey]
let request = CNContactFetchRequest.init(keysToFetch: keys as [CNKeyDescriptor])
do {
try contactStore.enumerateContacts(with: request, usingBlock: {(contact : CNContact, stop : UnsafeMutablePointer<ObjCBool>) -> Void in
self.dataArray.append(contact)
//1.获取姓名
let lastName = contact.familyName
let firstName = contact.givenName
print("姓名 : \(lastName)\(firstName)")
//2.获取电话号码
let phoneNumbers = contact.phoneNumbers
for phoneNumber in phoneNumbers {
print(phoneNumber.label ?? "")
print(phoneNumber.value.stringValue)
}
//3.回到主线程刷新UI
DispatchQueue.main.async {
self.tableView.reloadData()
}
})
} catch {
print(error)
}
}
func createLayout() -> Void {
tableView = UITableView.init(frame: self.view.bounds)
tableView.delegate = self
tableView.dataSource = self
tableView.tableFooterView = UIView()
self.view.addSubview(tableView)
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dataArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell(style: UITableViewCellStyle.subtitle
, reuseIdentifier: "contactCell");
if dataArray.isEmpty == false {
print(self.dataArray)
let contact = dataArray[indexPath.row]
let labelValue = (contact as AnyObject).phoneNumbers.first
cell.textLabel?.text = labelValue?.value.stringValue
cell.detailTextLabel?.text = (contact as AnyObject).familyName + (contact as AnyObject).givenName
}
return cell
}
打印结果
John Appleseed
_$!<Mobile>!$_ 888-555-5512
_$!<Home>!$_ 888-555-1212
---------------------------------1
Kate Bell
_$!<Mobile>!$_ (555) 564-8583
_$!<Main>!$_ (415) 555-3695
---------------------------------2
Anna Haro
_$!<Home>!$_ 555-522-8243
---------------------------------3
Daniel Higgins
_$!<Home>!$_ 555-478-7672
_$!<Mobile>!$_ (408) 555-5270
_$!<HomeFAX>!$_ (408) 555-3514
---------------------------------4
David Taylor
_$!<Home>!$_ 555-610-6679
---------------------------------5
Hank Zakroff
_$!<Work>!$_ (555) 766-4823
_$!<Other>!$_ (707) 555-1854
---------------------------------6