iOS系统通讯录授权,获取,修改,创建联系人

1、现在的很多应用程序中都会设计到手机系统通讯录的问题,下面就简单介绍一下iOS系统通讯录的
2、iOS9之前的系统通讯录有2个框架,分别是AddressBookUI/AddressBookUI.h // 系统带UI通讯录, AddressBook/AddressBook.h // 系统通讯录,需要自己手动搭建页面,
3、 AddressBookUI/AddressBookUI.h // 系统带UI通讯录,不用自己搭建页面,直接调用系统的就可以了,

ABPeoplePickerNavigationController *vc = [[ABPeoplePickerNavigationController alloc] init];
    vc.peoplePickerDelegate = self;

    [self presentViewController:vc animated:YES completion:nil];

遵守代理ABPeoplePickerNavigationControllerDelegate,并实现代理方法:

// ios7
- (void)peoplePickerNavigationControllerDidCancel:(ABPeoplePickerNavigationController *)peoplePicker{
    NSLog(@"111111");
    [peoplePicker dismissViewControllerAnimated:YES completion:nil];
}

// 在iOS7中选中一个联系人就会调用
// 返回一个BOOL值,NO代表不会进入到下一层(详情),YES代表会进入到下一层
- (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person{
    return NO;
}

// ios8选中一个联系人就会调用 实现这个方法之后,控制器不会进入到下一层(详情),直接dismiss
//- (void)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker didSelectPerson:(ABRecordRef)person{
//    NSLog(@"2222");
//}

// ios8选中某一个联系人的某一个属性时就会调用
- (void)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker didSelectPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier{
    NSLog(@"%@,%d,@%d",person,property,identifier);
}

这样的话,就能够直接利用系统的通讯录界面进行操作了,但是有一点就是,不能在界面上操作需求。

4、获取联系人。
AddressBook/AddressBook.h // 系统通讯录,需要自己手动搭建页面,这个框架只能够通过手动拿到联系人数据,然后自己搭建界面展示数据,并可以进行其他的需求操作。

(1)为了更方便的展示数据,首先创建person模型类:PeopleModel

#import 
@interface PeopleModel : NSObject

@property (nonatomic, copy) NSString *name; // 姓名
@property (nonatomic, copy) NSString *email; // 邮箱
@property (nonatomic, copy) NSString *tellPhone; // 电话
@property (nonatomic, strong) UIImage *iconImage; // 联系人头像

@property (nonatomic, assign) NSInteger sectionNumber; // section标题(用于按某一个属性排序,比如按照name排序)
@end

从通讯录中获取所有的联系人,并转换成person模型类,
(2)首先创建数据源,数据源一定要初始化,很多时候忘记初始化数据源会导致看不到数据,

@property (nonatomic ,retain) NSMutableArray *peoplePhoneData; // 用来存储联系人(分组)

// self.peoplePhoneData = [NSMutableArray array]; // 记得初始化数据源(这里就不用懒加载了)

(3)取得通讯录授权:程序在第一次使用的时候,会请求用户的授权,如果用户同意了,就加载数据,拒绝了,就给提示。如果不是第一次使用通讯录,就不再提示授权的提示框,但程序同样要走到下面的请求函数,这时系统会自动识别授权状态,granted=1,就是已经授权的,granted=0就是拒绝授权或者其他的,总之只有同意授权才可以拿数据的。

CFErrorRef *error = nil;

    ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(nil, error);
    ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) {
        NSLog(@"granted==%d",granted);

        if (granted) {
            NSLog(@"授权成功!");
            [self getUpAddBookViewPersonDataWithAddBook:addressBook];
        } else {
            NSLog(@"授权失败!");
            UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"授权失败" message:@"请在设置中打开访问权限" delegate:nil cancelButtonTitle:@"取消" otherButtonTitles:@"确定", nil];
            [alert show];
        }

    });

获取授权状态也可以用ABAddressBookGetAuthorizationStatus()获取授权状态,

kABAuthorizationStatusNotDetermined = 0, // 还没有决定是否授权(就是在第一次提示授权的时候)
kABAuthorizationStatusRestricted, // 有其他限制通讯录授权的状态
kABAuthorizationStatusDenied, // 拒绝授权
kABAuthorizationStatusAuthorized // 同意授权
(4)获取所有联系人并按照拼音排序(效果就是系统通讯录的排序效果),都是c语言的语法,与oc转化的时候是通过__bridge(桥接)来互相转换的

// 获取所有联系人并存储
- (void)getUpAddBookViewPersonDataWithAddBook:(ABAddressBookRef)addressBook
{
    // 获取所有联系人并存储
    CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople(addressBook);
    CFIndex peolpeCount = ABAddressBookGetPersonCount(addressBook); // 获取联系人个数

    NSMutableArray *peopleArray = [NSMutableArray array]; // 用来存储联系人模型

    // 获取联系人信息(将联系人转模型)
    for (NSInteger i = 0; i < peolpeCount; i++)
    {
        PeopleModel *model = [[PeopleModel alloc] init];
        ABRecordRef person = CFArrayGetValueAtIndex(allPeople, i); // 获取某一个联系人
        CFStringRef firstName = ABRecordCopyValue(person, kABPersonFirstNameProperty);
        CFStringRef lastName = ABRecordCopyValue(person, kABPersonLastNameProperty);
        CFStringRef fullName = ABRecordCopyCompositeName(person);


//         取出个人记录中的详细信息
//        NSString *firstNameLabel = (__bridge NSString *)(ABPersonCopyLocalizedPropertyName(kABPersonFirstNameProperty));
//        NSString *firstName = (__bridge NSString *)(ABRecordCopyValue(person, kABPersonFirstNameProperty));
//        NSString *lastNameLabel = (__bridge NSString *)(ABPersonCopyLocalizedPropertyName(kABPersonLastNameProperty));
//        NSString *lastName = (__bridge NSString *)(ABRecordCopyValue(person, kABPersonLastNameProperty));
//        NSLog(@"%@ %@ - %@ %@", lastNameLabel, lastName, firstNameLabel, firstName);


        // 读取name
        NSString *firstNameStr = (__bridge NSString *)firstName;
        NSString *lastNameStr = (__bridge NSString *)lastName;
        NSString *fullNameStr = (__bridge NSString *)fullName;

        if ( fullNameStr.length != 0) {
            firstNameStr = fullNameStr;
        } else if (lastNameStr.length!=0) {
            firstNameStr = [NSString stringWithFormat:@"%@ %@",firstNameStr,lastNameStr];
        }
        model.name = firstNameStr;
        // 读取邮箱
        ABMultiValueRef email = ABRecordCopyValue(person, kABPersonEmailProperty);
        NSInteger emailCount = ABMultiValueGetCount(email);
        for (NSInteger i = 0; i < emailCount; i++) {
            model.email = (__bridge NSString *)ABMultiValueCopyValueAtIndex(email, i);
        }

        // 读取电话
        ABMultiValueRef tellPhone = ABRecordCopyValue(person, kABPersonPhoneProperty);
        for (NSInteger i = 0; i < ABMultiValueGetCount(tellPhone); i++) {
            model.tellPhone = (__bridge NSString *)ABMultiValueCopyValueAtIndex(tellPhone, i);
        }


//        for (NSInteger i = 0; i < ABMultiValueGetCount(tellPhone); i++) {
////            获取复杂属性的方法
//            // 电话标签
//            CFStringRef phoneLabel = ABMultiValueCopyLabelAtIndex(tellPhone, i);
//            // 本地化电话标签
//            CFStringRef phoneLocalLabel = ABAddressBookCopyLocalizedLabel(phoneLabel);
//            // 电话号码 
//            CFStringRef phoneNumber = ABMultiValueCopyValueAtIndex(tellPhone, i);
//        }

        // 读取联系人头像
        NSData *iconData = (__bridge NSData *)ABPersonCopyImageData(person);
        model.iconImage = [UIImage imageWithData:iconData];

        [peopleArray addObject:model];
        if (firstName) {
            CFRelease(firstName);
        }
        if (lastName) {
            CFRelease(lastName);
        }
        if (fullName) {
            CFRelease(fullName);
        }

        CFRelease(email);
        CFRelease(tellPhone);
    }

    // 排序
    UILocalizedIndexedCollation *theCollation = [UILocalizedIndexedCollation currentCollation];
    for (PeopleModel *model in peopleArray) {
        NSInteger sect = [theCollation sectionForObject:model
                                collationStringSelector:@selector(name)]; // 根据模型的name字断排序
        model.sectionNumber = sect;
    }

    NSInteger highSection = [[theCollation sectionTitles] count];

    NSMutableArray *sectionArrays = [NSMutableArray arrayWithCapacity:highSection];

    for (int i=0; i<=highSection; i++) {
        NSMutableArray *sectionArray = [NSMutableArray arrayWithCapacity:1];
        [sectionArrays addObject:sectionArray];
    }

    for (PeopleModel *model in peopleArray) {
        [(NSMutableArray *)[sectionArrays objectAtIndex:model.sectionNumber] addObject:model];
    }

    // 排好序的联系人加入数组中
    for (NSMutableArray *sectionArray in sectionArrays) {
        int count = 0; // 统计name为nil的个数
        for (PeopleModel *model in sectionArray) {
            if (model.name.length==0) {
                count++;
            }
        }
        NSArray *sortedSection = [NSArray array];
        //        NSArray *sortedSection = [theCollation sortedArrayFromArray:sectionArray collationStringSelector:@selector(name)];
        if (count >= 2) { // 有2个以上name为nil,
            sortedSection = [NSArray arrayWithArray:sectionArray];
        } else {
            sortedSection = [theCollation sortedArrayFromArray:sectionArray collationStringSelector:@selector(name)];
        }
        [self.peoplePhoneData addObject:sortedSection];
    }
    [self.tableView reloadData];
}

在iOS的通讯录中的联系人的名字是有好几个的(firstName,lastName,fullName),所有按照需求来操作,并且手机号,邮箱都是有多个的,所有这些需求就需要按照设计需求来做了。

(5)索引实现。

// 索引序列
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView
{
    tableView.sectionIndexColor = [UIColor redColor];
    tableView.sectionIndexBackgroundColor=[UIColor clearColor];
    NSArray * array=[[NSArray arrayWithObject:@"★"] arrayByAddingObjectsFromArray:[[UILocalizedIndexedCollation currentCollation] sectionIndexTitles]];
    return [[NSArray arrayWithObject:UITableViewIndexSearch] arrayByAddingObjectsFromArray:array];
}

(6)section title
- (NSString )tableView:(UITableView )tableView titleForHeaderInSection:(NSInteger)section
{

NSString *title = [self.peoplePhoneData[section] count] ? [[[UILocalizedIndexedCollation currentCollation] sectionTitles] objectAtIndex:section]:nil;
return title;

}

5、修改联系人

// 修改联系人
- (void)updateRecod{

    // 1. 拿到通讯录
    ABAddressBookRef book = ABAddressBookCreateWithOptions(NULL, NULL);

    // 获取通讯录所有人
    CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople(book);

    // 拿到通讯录中的某一个联系人
    ABRecordRef people = CFArrayGetValueAtIndex(allPeople, 0);

    // 修改联系人信息
    ABRecordSetValue(people, kABPersonLastNameProperty, @"Li", NULL);

    // 保存通讯录
    ABAddressBookSave(book, NULL);


//    ABPersonHasImageData(people); // 判断通讯录中的联系人是否有图片
//    ABPersonSetImageData(people, <#CFDataRef imageData#>, <#CFErrorRef *error#>); // 设置联系人的图片数据

//    ABAddressBookRemoveRecord(<#ABAddressBookRef addressBook#>, <#ABRecordRef record#>, <#CFErrorRef *error#>) // 删除某一个联系人

//    ABAddressBookRevert(<#ABAddressBookRef addressBook#>) // 放弃更改信息
//    ABAddressBookHasUnsavedChanges(<#ABAddressBookRef addressBook#>) // 函数判断是否有未保存的修改
}

5、添加新的联系人

// 添加联系人
- (void)creadRecod{
    // 1. 创建联系人
    ABRecordRef people = ABPersonCreate();

    // 2. 设置联系人信息
    ABRecordSetValue(people, kABPersonLastNameProperty, @"san", NULL);
    ABRecordSetValue(people, kABPersonFirstNameProperty, @"zhang", NULL);

    // 创建电话号码
    ABMultiValueRef phones = ABMultiValueCreateMutable(kABMultiStringPropertyType);
    ABMultiValueAddValueAndLabel(phones, @"123456789", kABPersonPhoneMainLabel, NULL);
    ABMultiValueAddValueAndLabel(phones, @"888888", kABPersonPhoneHomeFAXLabel, NULL);

    ABRecordSetValue(people, kABPersonPhoneProperty, phones, NULL);

    // 3. 拿到通讯录
    ABAddressBookRef book = ABAddressBookCreateWithOptions(NULL, NULL);

    // 4. 将联系人添加到通讯录中
    ABAddressBookAddRecord(book, people, NULL);

    // 5. 保存通讯录
    ABAddressBookSave(book, NULL);
}

6、联系人的操作基本上就那么多了,有一些属性值是没有涉及到的,但是基本的操作方法都差不多。但是在iOS9之后,系统的通讯录框架改成了 ContactsUI/ContactsUI.h,这个后期会研究一下,并发表出来。

你可能感兴趣的:(iOS系统框架知识点)