通讯录

如何访问用户的通讯录:
在iOS中,有2个框架可以访问用户的通讯录
AddressBookUI.framework
AddressBookUI.framework目前不需要授权
提供了联系人列表界面、联系人详情界面、添加联系人界面等
一般用于选择联系人

AddressBook.framework
纯C语言的API,仅仅是获得联系人数据
没有提供UI界面展示,需要自己搭建联系人展示界面
里面的数据类型大部分基于Core Foundation框架,使用起来极其蛋疼

AddressBook.framework从iOS6开始,需要得到用户的授权才能访问通讯录,因此在使用之前,需要检查用户是否已经授权
获得通讯录的授权状态:ABAddressBookGetAuthorizationStatus()

授权状态
kABAuthorizationStatusNotDetermined
用户还没有决定是否授权你的程序进行访问

kABAuthorizationStatusRestricted
iOS设备上一些许可配置阻止程序与通讯录数据库进行交互

kABAuthorizationStatusDenied
用户明确的拒绝了你的程序对通讯录的访问

kABAuthorizationStatusAuthorized
用户已经授权给你的程序对通讯录进行访问

申请访问通讯录
//实例化通讯录对象
ABAddressBookRefaddressBook= ABAddressBookCreateWithOptions(NULL, NULL);
ABAddressBookRequestAccessWithCompletion(addressBook, ^(boolgranted, CFErrorReferror) {
    if(granted) {
       NSLog(@"授权成功!");
    } else{
       NSLog(@"授权失败!");
    }
});
CFRelease(addressBook);

提示:申请通讯录访问授权的代码,通常放在AppDelegate中
联系人属性定义
所有的属性常量值都定义在了ABPerson.h头文件中 
联系人属性包括以下类型:
简单属性:姓、名等
多重属性:电话号码、电子邮件等
组合属性:地址等

注意:使用ABRecordCopyValue可以从一条Person记录中获取到对应的记录,但是后续处理则需要根据记录的具体类型加以区分

简单属性
一个联系人就是一个ABRecordRef,每个联系人都有自己的属性,比如名字、电话、邮件等
使用ABRecordCopyValue函数可以从ABRecordRef中获得联系人的简单属性(例如:一个字符串)
ABRecordCopyValue函数接收2个参数
第1个参数是ABRecordRef实例
第2个参数是属性关键字,定义在ABPerson.h中
ABPersonCopyLocalizedPropertyName函数可以根据指定的关键字获取对应的标签文本

获得所有的联系人数据
//获取所有联系人记录
CFArrayRefarray = ABAddressBookCopyArrayOfAllPeople(addressBook);
NSIntegercount = CFArrayGetCount(array);

for(NSIntegeri = 0; i < count; ++i) {
   //取出一条记录
    ABRecordRefperson = CFArrayGetValueAtIndex(array, i);
    
    //取出个人记录中的详细信息
          //名
    CFStringReffirstNameLabel= ABPersonCopyLocalizedPropertyName(kABPersonFirstNameProperty);
    CFStringReffirstName= ABRecordCopyValue(person, kABPersonFirstNameProperty);
    CFStringReflastNameLabel= ABPersonCopyLocalizedPropertyName(kABPersonLastNameProperty);
    //姓
    CFStringReflastName= ABRecordCopyValue(person, kABPersonLastNameProperty);
    
    NSLog(@"%@ %@ - %@ %@", lastNameLabel, lastName, firstNameLabel, firstName);
}
CoreFoundation与 Foundation之间的桥接
// 1. 获取通讯录引用
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, nil);
// 2. 获取所有联系人记录
NSArray *array = (__bridge NSArray *)(ABAddressBookCopyArrayOfAllPeople(addressBook));
for (NSInteger i = 0; i < array.count; i++) {
    // 取出一条记录
        ABRecordRef person = (__bridge ABRecordRef)(array[i]);
    // 取出个人记录中的详细信息
        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);
}
CFRelease(addressBook);

多重属性

联系人的有些属性值就没这么简单,一个属性可能会包含多个值
比如邮箱,分为工作邮箱、住宅邮箱、其他邮箱等
比如电话,分为工作电话、住宅电话、其他电话等
如果是复杂属性,那么ABRecordCopyValue函数返回的就是ABMultiValueRef类型的数据,例如邮箱或者电话
// 取电话号码
ABMultiValueRef phones = ABRecordCopyValue(person, kABPersonPhoneProperty);
// 取记录数量
NSInteger phoneCount = ABMultiValueGetCount(phones);
// 遍历所有的电话号码
for (NSInteger i = 0; i < phoneCount; i++) {
获取复杂属性的方法
// 电话标签
CFStringRef phoneLabel = ABMultiValueCopyLabelAtIndex(phones, i);
// 本地化电话标签
CFStringRef phoneLocalLabel = ABAddressBookCopyLocalizedLabel(phoneLabel);
// 电话号码
CFStringRef phoneNumber = ABMultiValueCopyValueAtIndex(phones, i);

添加联系人的步骤
添加联系人的步骤
通过ABPersonCreate函数创建一个新的联系人(返回ABRecordRef)
通过ABRecordSetValue函数设置联系人的属性
通过ABAddressBookAddRecord函数将联系人添加到通讯录数据库中
通过ABAddressBookSave函数保存刚才所作的修改

可以通过ABAddressBookHasUnsavedChanges函数判断是否有未保存的修改
当决定是否更改通讯录数据库后,你可以分别使用 AbAddressBookSave 或 ABAddressBookRevert 方式来保存或放弃更改 

添加群组的步骤
添加群组的步骤大体和添加联系人一致
通过ABPersonCreate函数创建一个新的组(返回ABRecordRef)
通过ABRecordSetValue函数设置组名
通过ABAddressBookAddRecord函数将组添加到通讯录数据库中
通过ABAddressBookSave函数保存刚才所作的修改

操作联系人的头像
想操作联系人的头像,有以下函数
BPersonHasImageData
判断通讯录中的联系人是否有图片 

ABPersonCopyImageData 
取得图片数据(假如有的话)

ABPersonSetImageData 
设置联系人的图片数据 

AddressBookUI.framework方式的代码:

#import "ViewController.h"
#import 

@interface ViewController () 

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    // 1.创建选择联系人的界面
    ABPeoplePickerNavigationController *ppnc = [[ABPeoplePickerNavigationController alloc] init];
    
    // 2.设置代理
    ppnc.peoplePickerDelegate = self;
    
    // 3.弹出选择联系人界面
    [self presentViewController:ppnc animated:YES completion:nil];
}

#pragma mark - 实现ABPeoplePickerNavigationController的代理方法
// 选中某一个联系人的时候,会执行该代理方法
// 如果实现了该方法,那么就不会进入联系人的详细界面
- (void)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker didSelectPerson:(ABRecordRef)person
{
    /*
     __bridge NSString * : 将CoreFoundation框架的对象所有权交给Foundation框架来使用,但是Foundation框架中的对象并不能管理该对象内存
     __bridge_transfer NSString * : 将CoreFoundation框架的对象所有权交给Foundation来管理,如果Foundation中对象销毁,那么我们之前的对象(CoreFoundation)会一起销毁
     */
    // 1.获取选中联系人的姓名(姓lastname和名firstname)
    CFStringRef firstname = ABRecordCopyValue(person, kABPersonFirstNameProperty);
    CFStringRef lastname = ABRecordCopyValue(person, kABPersonLastNameProperty);
    NSString *firstName = (__bridge_transfer NSString *)(firstname);
    NSString *lastName = (__bridge_transfer NSString *)(lastname);
    NSLog(@"%@ %@", firstName, lastName);
    
    // 2.获取联系人的电话号码
    ABMultiValueRef phones = ABRecordCopyValue(person, kABPersonPhoneProperty);
    CFIndex count = ABMultiValueGetCount(phones);
    for (CFIndex i = 0; i < count; i++) {
        NSString *phoneLabel = (__bridge_transfer NSString *)ABMultiValueCopyLabelAtIndex(phones, i);
        NSString *phoneValue = (__bridge_transfer NSString *)ABMultiValueCopyValueAtIndex(phones, i);
        NSLog(@"label : %@ value : %@", phoneLabel, phoneValue);
    }
    
    // 3.释放不再使用的对象
    CFRelease(phones);
}

// 选择某一个联系人的某一个属性时,会执行该方法
// property选中的属性
// identifier : 每一个属性都由一个对应标示
// 如果实现了该方法,那么选中一个联系人的属性时,就会推出控制器.不会进入下一个页面
- (void)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker didSelectPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier
{
    NSLog(@"选择了某一个联系人的某一个属性");
}

// 点击了取消按钮会执行该方法
- (void)peoplePickerNavigationControllerDidCancel:(ABPeoplePickerNavigationController *)peoplePicker
{
    
}

@end
AddressBook.framework方式的代码:

#import "AppDelegate.h"
#import 

@interface AppDelegate ()

@end

@implementation AppDelegate


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    
    // 1.获取授权的状态
    ABAuthorizationStatus status = ABAddressBookGetAuthorizationStatus();
    
    // 2.判断授权状态,如果是未决定状态,才需要请求
    if (status == kABAuthorizationStatusNotDetermined) {
        // 2.1.创建通信录对象
        ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, NULL);
        
        // 2.2.请求授权
        ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) {
            if (granted) {
                NSLog(@"授权成功");
            } else {
                NSLog(@"授权失败");
            }
        });
    }
    
    return YES;
}
#import "ViewController.h"
#import 

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    // 1.获取授权的状态
    ABAuthorizationStatus status = ABAddressBookGetAuthorizationStatus();
    
    // 2.如果用户已经授权
    if (status != kABAuthorizationStatusAuthorized) return;
    
    // 3.创建通信录对象
    ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, NULL);
    
    // 4.从通信录对象中,将所有的联系人拷贝出来
    CFArrayRef peopleArray = ABAddressBookCopyArrayOfAllPeople(addressBook);
    
    // 5.遍历所有的联系人(每一个联系人都是一条记录)
    CFIndex peopleCount = CFArrayGetCount(peopleArray);
    for (CFIndex i = 0; i < peopleCount; i++) {
        
        // 6.获取到联系人
        ABRecordRef person = CFArrayGetValueAtIndex(peopleArray, i);
        
        // 7.获取姓名
        NSString *lastname = (__bridge_transfer NSString *)ABRecordCopyValue(person, kABPersonLastNameProperty);
        NSString *firstName = (__bridge_transfer NSString *)ABRecordCopyValue(person, kABPersonFirstNameProperty);
        NSLog(@"%@ %@", lastname, firstName);
    }
    
    // 8.释放不再使用的对象
    CFRelease(peopleArray);
    CFRelease(addressBook);
}

@end


AddressBook.framework方式
邮箱、手机号码、姓名
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, NULL);
  //拿到所有联系人
  CFArrayRef peopleArray = ABAddressBookCopyArrayOfAllPeople(addressBook);
  //数组数量
  CFIndex peopleCount = CFArrayGetCount(peopleArray);
  for (int i = 0; i < peopleCount; i++) {
      //拿到一个人
      ABRecordRef person = CFArrayGetValueAtIndex(peopleArray, i);
      //拿到姓名
      //姓
      NSString *lastNameValue = (__bridge_transfer NSString *)ABRecordCopyValue(person, kABPersonLastNameProperty);
      //名
      NSString *firstNameValue = (__bridge_transfer NSString *)ABRecordCopyValue(person, kABPersonFirstNameProperty);

      //拿到多值电话
      ABMultiValueRef phones = ABRecordCopyValue(person, kABPersonPhoneProperty);
      //多值数量
      CFIndex phoneCount = ABMultiValueGetCount(phones);
      for (int j = 0; j < phoneCount ; j++) {
          //电话标签本地化(例如是住宅,工作等)
          NSString *phoneLabel = (__bridge_transfer NSString *)ABAddressBookCopyLocalizedLabel(ABMultiValueCopyLabelAtIndex(phones, j));
          //拿到标签下对应的电话号码
          NSString *phoneValue = (__bridge_transfer NSString *)ABMultiValueCopyValueAtIndex(phones, j);
      }
      CFRelease(phones);

      //邮箱多值
      ABMultiValueRef emails = ABRecordCopyValue(person, kABPersonEmailProperty);
      CFIndex emailCount = ABMultiValueGetCount(emails);
      for (int k = 0; k < emailCount; k++) {
          NSString *emailLabel = (__bridge_transfer NSString *)ABAddressBookCopyLocalizedLabel(ABMultiValueCopyLabelAtIndex(emails, k));
          NSString *emailValue = (__bridge_transfer NSString *)ABMultiValueCopyValueAtIndex(emails, k);
      }
      CFRelease(emails);
  }
  CFRelease(addressBook);
  CFRelease(peopleArray);

添加联系人
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, NULL);
  for (IABPerson *iPerson in array) {
      //创建一个联系人
      ABRecordRef person = ABPersonCreate();
      //新增姓名
      NSString *Name = iPerson.Name;
      //转换为CFString
      CFStringRef lastName = (__bridge_retained CFStringRef)Name;
      //设置属性
      ABRecordSetValue(person, kABPersonLastNameProperty, lastName, NULL);
      CFRelease(lastName);
      //新增电话
      ABMultiValueRef phones = ABMultiValueCreateMutable(kABMultiStringPropertyType);
          //手机标签设置值
          CFStringRef mobile = (__bridge_retained CFStringRef)iPerson.MobilePhone;
          ABMultiValueAddValueAndLabel(phones, mobile, kABPersonPhoneMobileLabel, NULL);
          CFRelease(mobile);
          //住宅标签设置值
          CFStringRef homeTel = (__bridge_retained CFStringRef)iPerson.HomeTel;
          ABMultiValueAddValueAndLabel(phones, homeTel, kABHomeLabel, NULL);
          CFRelease(homeTel);
          //工作标签设置值
          CFStringRef workTel = (__bridge_retained CFStringRef)iPerson.WorkTel;
          ABMultiValueAddValueAndLabel(phones, workTel, kABWorkLabel, NULL);
          CFRelease(workTel);
          //其他标签设置值
          CFStringRef otherTel = (__bridge_retained CFStringRef)iPerson.OtherTel;
          ABMultiValueAddValueAndLabel(phones, otherTel, kABOtherLabel, NULL);
          CFRelease(otherTel);
      //为联系人的电话多值 设置值
      ABRecordSetValue(person, kABPersonPhoneProperty, phones, NULL);

      //新增邮箱
      ABMultiValueRef emails = ABMultiValueCreateMutable(kABPersonEmailProperty);
          //住宅邮箱设置值
          CFStringRef email = (__bridge_retained CFStringRef)iPerson.Email;
          ABMultiValueAddValueAndLabel(emails, email, kABHomeLabel, NULL);
          CFRelease(email);
      //为联系人添加邮箱多值
      ABRecordSetValue(person, kABPersonEmailProperty, emails, NULL);
      //给通讯录添加联系人
      ABAddressBookAddRecord(addressBook, person, NULL);
      CFRelease(person);
      CFRelease(phones);
      CFRelease(emails);
  }
  //保存通讯录,一定要保存
  ABAddressBookSave(addressBook, NULL);
  CFRelease(addressBook);

你可能感兴趣的:(通讯录)