iOS 通讯录编程【总结】
来源:互联网 发布:人工智能技术及应用 编辑:程序博客网 时间:2024/04/24 23:54
第一大块儿:读取通讯录
1、iOS 6以上系统,争取获取用户同意:
-(id)init{ self = [super init]; [self createdABHandle]; bool isAuthorized = [self isAuthorizedAddressBook]; if (!isAuthorized) { ABAddressBookRequestAccessWithCompletion(_addressBook, ^(bool granted, CFErrorRef error){ if (granted){ //[self createAddressBuddyData]; } }); } return self;}看看isAuthorizedAddressBook的内容:
- (BOOL)isAuthorizedAddressBook { if (SYSTEM_VERSION <= 6.0){ return YES; } // ABAuthorizationStatus status = ABAddressBookGetAuthorizationStatus(); if (status == kABAuthorizationStatusNotDetermined) { return NO; } else if(status == kABAuthorizationStatusAuthorized) { return YES; } else if (status == kABAuthorizationStatusDenied) { return NO; } return NO;}
2、获取联系人,获取联系人分组
ABAddressBookRef addressBook =ABAddressBookCreate();NSArray* allPeople = CFBridgingRelease(ABAddressBookCopyArrayOfAllPeople (addressBook));NSArray* allGroups = CFBridgingRelease(ABAddressBookCopyArrayOfAllGroups(addressBook));for (id person in (NSArray *) allPeople) [self logContact:person];for (id group in (NSArray *) allGroups) [self logGroup:group];CFRelease(addressBook);
3、联系人字段获取技巧:
● 获取个人或群体完整名称。例如:NSString* name = (NSString*)ABRecordCopyCompositeName(record);
● 获取联系人ID ABRecordID recId = ABRecordGetRecordID(record);
● 获取电话,邮箱列表,生日等,多键值的方法 例如:ABMultiValueRef phoneNumbersArr = ABRecordCopyValue(record, kABPersonPhoneProperty);
● 获取联系人分组名称 CFStringRef name = ABRecordCopyValue(group,kABGroupNameProperty);
● 获取联系人分组ID ABRecordID recId = ABRecordGetRecordID(group);
在获取多值的属性时候需要注意:获取地址的时候,多键值有嵌套。
代码如下:
NSArray *allPeople = ABAddressBookCopyArrayOfAllPeople(addressBook);int i;for (i = 0; i < [allPeople count]; i++) {ABRecordRef record = [allPeople objectAtIndex:i];ABMutableMultiValueRef multiValue = ABRecordCopyValue(record, kABPersonAddressProperty);for(CFIndex i=0;i<ABMultiValueGetCount(multiValue);i++){NSString* HomeLabel=(NSString*)ABMultiValueCopyLabelAtInde x(multiValue, i);if([HomeLabel isEqualTo:@"_$!<Home>!$_"]){ CFDictionaryRef dict = ABMultiValueCopyValueAtIndex(multiValueArr, i); NSString* street =CFBridgingRelease( CFDictionaryGetValue(dict, kABPersonAddressStreetKey)); NSString* city =CFBridgingRelease( CFDictionaryGetValue(dict, kABPersonAddressCityKey)); NSString* country =CFBridgingRelease(CFDictionaryGetValue(dict, kABPersonAddressCountryKey)); CFRelease(dict); NSString *syntheticAddress = [NSString stringWithFormat:@"%@, %@, %@" ,(street?street:@"") ,(city?city:@"") ,(country?country:@"")];}
不能直接调用ABMultiValueCopyValueAtIndex,然后强转成NSString*
4、删除联系人或者群组
ABAddressBookRemoveRecord(addressBook, people, NULL);
ABAddressBookSave(addressBook, NULL);
第二大块儿:写入通讯录
/* 更新联系人,比如phoneTypePairArr为空,那么程序把一个空的ABMultiValueRef写入addressBook,达到删除的效果。 */-(BOOL) updateToAB:(ABRecordRef)person withContact:(RCSContact*)contact{ ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, nil); // 保存到联系人对象中,如果属性为nil,则表示要删除 //lastname NSString* lastName = contact.lastName.length?contact.lastName:nil; ABRecordSetValue(person, kABPersonLastNameProperty, (__bridge CFStringRef)lastName, NULL); //firstName NSString* firstName = [contact.firstName length]?contact.firstName:nil; ABRecordSetValue(person, kABPersonFirstNameProperty, (__bridge CFStringRef)firstName, NULL); //birthday if ([contact.birthday length]) { NSDateFormatter *inputFormatter = [[NSDateFormatter alloc] init]; [inputFormatter setLocale:[[NSLocale alloc] initWithLocaleIdentifier:@"zh_CN"]]; [inputFormatter setDateFormat:@"yyyy-MM-dd"]; NSDate* inputDate = [inputFormatter dateFromString:contact.birthday]; ABRecordSetValue(person, kABPersonBirthdayProperty, (__bridge CFDateRef)inputDate, NULL); }else{ ABRecordSetValue(person, kABPersonBirthdayProperty, NULL, NULL); } //company name NSString* companyName = [contact.companyName length]?contact.companyName:nil; ABRecordSetValue(person, kABPersonOrganizationProperty, (__bridge CFStringRef)companyName, NULL); //company duty NSString* companyDuty = [contact.companyDuty length]?contact.companyDuty:nil; ABRecordSetValue(person, kABPersonJobTitleProperty, (__bridge CFStringRef)companyDuty, NULL); // ABMultiValueRef类似是Objective-C中的NSMutableDictionary ABMultiValueRef mv = ABMultiValueCreateMutable(kABMultiStringPropertyType); NSArray* tmpArr = [NSArray arrayWithArray:contact.phoneTypePairArr]; for (PhoneTypePair* p in tmpArr) { if ([p.content length]==0) { continue; } NSString* label = [_typeDic_ForWrite objectForKey:p.type]; ABMultiValueIdentifier mi = ABMultiValueAddValueAndLabel(mv, (__bridge CFStringRef)p.content, (__bridge CFStringRef)label, &mi); } ABRecordSetValue(person, kABPersonPhoneProperty, mv, NULL); if (mv) { CFRelease(mv);} //设置邮箱 ABMutableMultiValueRef emailCFArray = ABMultiValueCreateMutable(kABStringPropertyType); tmpArr = [NSArray arrayWithArray:contact.eMailArr]; for (PhoneTypePair* p in tmpArr) { //邮件的话 if ([p.content length]==0) { continue; } NSString* label = [_typeDic_ForWrite objectForKey:p.type]; ABMultiValueAddValueAndLabel(emailCFArray,(__bridge CFStringRef)(p.content),(__bridge CFStringRef)label,NULL); } ABRecordSetValue(person, kABPersonEmailProperty, emailCFArray, NULL); if(emailCFArray){CFRelease(emailCFArray);} //设置地址 ABMutableMultiValueRef multiAddress = ABMultiValueCreateMutable(kABMultiDictionaryPropertyType); tmpArr = [NSArray arrayWithArray:contact.addressArr]; for (PhoneTypePair* p in tmpArr) { //地址的话 if ([p.content length]==0) { continue; } NSMutableDictionary *addressDictionary = [[NSMutableDictionary alloc] init]; [addressDictionary setObject:[p.content mutableCopy] forKey:(NSString *)kABPersonAddressStreetKey]; [addressDictionary setObject:@"" forKey:(NSString *)kABPersonAddressCityKey]; [addressDictionary setObject:@"" forKey:(NSString *)kABPersonAddressStateKey]; [addressDictionary setObject:@"" forKey:(NSString *)kABPersonAddressZIPKey]; [addressDictionary setObject:@"" forKey:(NSString *)kABPersonAddressCountryCodeKey]; //set label NSString* label = [_typeDic_ForWrite objectForKey:p.type]; ABMultiValueAddValueAndLabel(multiAddress, CFBridgingRetain(addressDictionary), (__bridge CFStringRef)label, NULL); } ABRecordSetValue(person, kABPersonAddressProperty, multiAddress, NULL); if (multiAddress) {CFRelease(multiAddress);} // 设置头像属性 ABPersonRemoveImageData(person, NULL); ABAddressBookAddRecord(addressBook, person, nil); //设置头像 NSData *data = UIImagePNGRepresentation(contact.portrait); ABAddressBookSave(addressBook, NULL); if ([data length]==0) { ABPersonRemoveImageData(person, NULL); }else{ CFDataRef cfData = CFDataCreate(NULL, [data bytes], [data length]); ABPersonSetImageData(person, cfData, nil); } // 将新建的联系人添加到通讯录中,保存通讯录 ABAddressBookAddRecord(addressBook, person, NULL); bool isSucess = ABAddressBookSave(addressBook, NULL); NSLog (@"添加一个人到数据库成功[%d]",isSucess); // 释放通讯录对象的引用 if (addressBook) { CFRelease(addressBook); } return isSucess;
例如:第35,47,61行,都是采用拷贝数组,防止多线程下读、写数组,导致enumed error
第三大块儿:监听通讯录变更
客户端代码需要这么实现:
/* 移除注册函数 */-(void)dealloc{ ABAddressBookUnregisterExternalChangeCallback(_addressBook, ContactsChangeCallback, nil);}/* 注册回调函数 */- (id)init { self = [super init]; [self addressBookHandle]; ABAddressBookRegisterExternalChangeCallback(_addressBook, ContactsChangeCallback, nil); return self;}/* 回调函数,实现自己的逻辑。 */void ContactsChangeCallback (ABAddressBookRef addressBook, CFDictionaryRef info, void *context){ NSLog(@"ContactsChangeCallback");}
_addressBook是通讯录句柄。虽然有监听的接口,但是参数info总是空的。
另外:当本APP编辑系统通讯录时候,不会收到通知;通知可能有多个,这时候可以采取:“只处理第一个通知,淹没后面的通知。”;也可以采取信号量机制,对变更通知一个个在线程中处理,防止界面卡顿。
另外:在添加新的联系人的时候,使用ABNewPersonViewController。特别注意,一定要处理好它的代理:
// Called when the user selects Save or Cancel. If the new person was saved, person will be // a valid person that was saved into the Address Book. Otherwise, person will be NULL. // It is up to the delegate to dismiss the view controller.- (void)newPersonViewController:(ABNewPersonViewController *)newPersonView didCompleteWithNewPerson:(ABRecordRef)person;处理不好,造成APP崩溃。我的处理是这样的:
[self.navigationController popToViewController:self animated:YES];
监听规则:
当App活跃(前台+后台保活期间)的时候,当通讯录修改的时候,会收到通知
当App不活跃的时候(挂起的时候),App收不到通知;而是,当App到前台的时候收到延迟的通知。
生成vcard
/************************************************* * @brief 获取通讯录联系列表的vcard * @param 无 * @retun 无 *************************************************/- (void)getLocalAddressBookvCard { CFArrayRef persons = ABAddressBookCopyArrayOfAllPeople(_addressBook); CFDataRef vcards = (CFDataRef)ABPersonCreateVCardRepresentationWithPeople(persons); NSString *vcardString = [[NSString alloc] initWithData:(__bridge NSData *)vcards encoding:NSUTF8StringEncoding]; NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *folderPath = [paths objectAtIndex:0]; NSString *filePath = [folderPath stringByAppendingPathComponent:@"contacts.vcf"]; NSLog(@"path = %@",filePath); [vcardString writeToFile:filePath atomically:YES encoding:NSUTF8StringEncoding error:nil];}
生成到document目录下的contacts.vcf文件
还可以用下面的办法,更适合生成单个crad
+(NSData*)exportContactsToVcard:(NSArray*)contacts{ NSMutableArray *people = [NSMutableArray arrayWithCapacity:contacts.count]; ABAddressBookRef ab = ABAddressBookCreate(); for (Contact *contact in contacts) { ABRecordRef person = ABAddressBookGetPersonWithRecordID(ab,contact.contactId); [people addObject:(__bridge id)person]; } NSData *vCard = (__bridge NSData*)ABPersonCreateVCardRepresentationWithPeople((__bridge CFArrayRef) people); return vCard;}
ABAddressBookRef book = ABAddressBookCreate();ABRecordRef defaultSource = ABAddressBookCopyDefaultSource(book);CFArrayRef vCardPeople = ABPersonCreatePeopleInSourceWithVCardRepresentation(defaultSource, vCardData);for (CFIndex index = 0; index < CFArrayGetCount(vCardPeople); index++) { ABRecordRef person = CFArrayGetValueAtIndex(vCardPeople, index); ABAddressBookAddRecord(book, person, NULL);}CFRelease(vCardPeople);CFRelease(defaultSource);ABAddressBookSave(book, NULL);CFRelease(book);
- iOS 通讯录编程【总结】
- IOS编程之通讯录
- IOS通讯录操作总结
- IOS通讯录编程 获取通讯录信息
- iOS编程------singleton_AddressBook 单例模式 通讯录
- ios手机功能:电话 短信 通讯录 总结
- iOS通讯录
- iOS通讯录
- 通讯录 ios
- iOS通讯录
- iOS通讯录
- iOS编程-------AddressBook_自定义cell 自定义单元格通讯录
- iOS网络编程总结
- iOS网络编程总结
- ios编程总结
- ios 网络编程总结
- IOS 网络编程总结
- iOS网络编程总结
- 初学制作计算器 m+ m- mc 等没有实现 等后期优化 因为初学 所以代码不好 见谅
- strcpy和memcpy的区别
- [JavaScript]-----匿名函数与闭包
- 演讲大厅安排
- AMQP协议一
- iOS 通讯录编程【总结】
- 归并排序-归并排序
- java使用泛型不使用任何库函数实现栈
- Jquery中的选择器
- 循环小数
- 超全的Labview VISA驱动,所有版本都有,我的是LABVIEW8.2的,4.5版本就有!
- 用树状数组解决区间查询问题
- Extjs Grid翻页后再刷新无法回到第一页
- uva 474 - Heads / Tails Probability(递推)