您的位置:首页 > 其它

调用系统通讯录

2016-01-11 15:43 330 查看
通常我们在iOS项目中想到通讯录往往有两大方面的需求。一个是让用户自己从通讯录中选择朋友然后我们获取数据完成业务,另一个是项目通过读取用户通讯录信息来完成相应的数据处理,即用户自主行为和应用调取行为。

首先谈一下用户自主调用通讯录。这里我们会使用系统控件ABPeoplePickerNavigationController。由于是用户自主行为,调用它我们无须向用户请求授权。但是ABPeoplePickerNavigationController给我们提供的操作很有限,在界面上我们只能修改一下导航条背景色,标题颜色之类的属性。对我们更有用的数据则是通过ABPeoplePickerNavigationControllerDelegate的相关方法完成的。这里注意一下,iOS8替换了一个代理方法

- (void)peoplePickerNavigationController:(ABPeoplePickerNavigationController*)peoplePicker didSelectPerson:(ABRecordRef)person NS_AVAILABLE_IOS(8_0);

这也是我们获取数据的主要代理方法。此方法可以看到我们唯一可以获得可操作的数据就是(ABRecordRef)person。下面是获取person数据中手机号的实现:
NSString* name = (__bridge_transfer NSString*)ABRecordCopyCompositeName(person);    //获取联系人电话    ABMutableMultiValueRef phoneMulti = ABRecordCopyValue(person, kABPersonPhoneProperty);    NSMutableArray *phones = [[NSMutableArray alloc] init];    int i;    for (i = 0; i < ABMultiValueGetCount(phoneMulti); i++)    {        NSString *aPhone = (__bridge_transfer NSString*)ABMultiValueCopyValueAtIndex(phoneMulti, i);        NSString *aLabel = (__bridge_transfer NSString*)ABMultiValueCopyLabelAtIndex(phoneMulti, i);        if (aPhone.length < 11) {            break ;        }        if([aLabel isEqualToString:@"_$!<Mobile>!$_"]){            [phones addObject:[self reStringFormatter:aPhone]];        }else{            [phones addObject:[self reStringFormatter:aPhone]];        }    }    //解决phoneMulti的内存泄露    CFRelease(phoneMulti); //AB..... 类不支持ARC,需要手动内存管理,一定要注意内存!


再谈谈应用调取通讯录信息的方式。这里我们需要让用户授权应用调取通讯录的权限,这样我们可以对通讯录进行增删改查操作。具体的,我们使用ABAddressBookRef和其相关的一系列类。注意,他们都不是iOS类,不支持现金常用的ARC自动管理内存,所以要特别注意内存问题,防止内存泄露。

这里结合韩韩自身的实际应用,谈谈这种调用通讯录的方法。我的目的是读取通讯录,根据已有的手机号码数据查找相应的用户名,然后显示。在ABAddressBookRef系列类中有根据名字查找通讯录单元信息(ABRecordRef)的方法,但是恰好没有根据手机号查找通讯录单元信息的方法。那么只能通过获得通讯录全部信息,然后遍历并比对手机号信息来查找了。

1)询问用户获得通讯录读取权限:

if (ABAddressBookRequestAccessWithCompletion != NULL) {    //检查是否是iOS6        ABAddressBookRef abRef = ABAddressBookCreateWithOptions(NULL, NULL);        if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusNotDetermined) {            //如果该应用从未申请过权限,申请权限            ABAddressBookRequestAccessWithCompletion(abRef, ^(bool granted, CFErrorRef error) {                //根据granted参数判断用户是否同意授予权限                if (granted) {                    //查询所有,这里我们可以用来进行下一步操作                }            });        } else if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusAuthorized) {            //如果权限已经被授予            //查询所有,这里我们可以用来进行下一步操作        } else {            //如果权限被收回,只能提醒用户去系统设置菜单中打开        }        if(abRef){            CFRelease(abRef);        }    }

2)获取全部通讯录单元信息(ABRecordRef)

ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, NULL);    //获取联系人电话    CFArrayRef allPerson = ABAddressBookCopyArrayOfAllPeople(addressBook);//取全部联系人

3)获取全部通讯录单元信息(获取名字)

ABRecordRef aPerson = CFArrayGetValueAtIndex(allPerson, (CFIndex)i);        ABMutableMultiValueRef phoneMulti = ABRecordCopyValue(aPerson, kABPersonPhoneProperty);        //按照汉语姓名规则拼接用户名,因为有前、中、后名,这里要注意  	ABMutableMultiValueRef firstNameMulti = ABRecordCopyValue(aPerson, kABPersonFirstNameProperty);  	ABMutableMultiValueRef middleNameMulti = ABRecordCopyValue(aPerson, kABPersonMiddleNameProperty);	ABMutableMultiValueRef lastNameMulti = ABRecordCopyValue(aPerson, kABPersonLastNameProperty);   	NSString *firsNameString    = [self dealNullString:(__bridge_transfer NSString*)firstNameMulti];  	NSString *middleNameString  = [self dealNullString:(__bridge_transfer NSString*)middleNameMulti];   	NSString *lastNameString    = [self dealNullString:(__bridge_transfer NSString*)la	NSString *nameString = [NSString stringWithFormat:@"%@%@%@",lastNameString,middleNameString,firsNameString]stNameMulti];

4)获取全部通讯录单元信息(获取手机号)

NSMutableArray *phones = [[NSMutableArray alloc] init];    for (int i = 0; i < ABMultiValueGetCount(phoneMulti); i++)    {	//phoneMulti 为ABMutableMultiValueRef类型        NSString *aPhone = (__bridge_transfer NSString*)ABMultiValueCopyValueAtIndex(phoneMulti, i);        NSString *aLabel = (__bridge_transfer NSString*)ABMultiValueCopyLabelAtIndex(phoneMulti, i);        TBDPRINT(@"PhoneLabel:%@ Phone#:%@",aLabel,aPhone);        if (aPhone.length < 11) {            break ;        }        if([aLabel isEqualToString:@"_$!<Mobile>!$_"]){            [phones addObject:[self reStringFormatter:aPhone]];        }else{            [phones addObject:[self reStringFormatter:aPhone]];        }    }

剩下的就是比对和数据处理了。运用ABAddressBookRef还可以实现写入数据、删除数据的功能。待以后进一步研究。

在iOS9系统中,新发现关于通讯录的问题。现象,在调用通讯录的页面,当打开通讯录正常点选某条电话信息后关闭通讯录之后,在某些页面获取当前最上层window的时候,发现获取到了如
remoteKeyWindow 的一个window,为iOS9新发现的状况,这会造成一些window操作的错误。且到现在为止未查到相关资料。为了降低影响,采取了非根本的方式解决,即在关闭通讯录时,取一个当前页面的textField,在关闭通讯录之后取消该textField的第一响应者。经实测,问题得到了解决。但究其根本原因还不知晓。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: