iOS 通讯录编程【总结】
第一大块儿:读取通讯录
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
第三大块儿:监听通讯录变更
client代码须要这么实现:
/*
移除注冊函数
*/
-(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;
}
从vcard生成person
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通讯录相关知识-浅析
本文来自于:贞娃儿的博客 http://blog.sina.com.cn/zhenwawaer 在开发一些应用中,我们如果需要iPhone设备中的通讯录信息.或者,需要开发通讯录相关的一些功能.那 ...
- iOS网络编程模型
iOS网络编程层次结构也分为三层: Cocoa层:NSURL,Bonjour,Game Kit,WebKit Core Foundation层:基于 C 的 CFNetwork 和 CFNetServ ...
- IOS网络编程——第三方类库
IOS网络编程——第三方类库 目录 概述 ASIHttpRequest AFNetworking 其他 概述 ASIHttpRequest AFNetworking 其他
- iOS 6编程Cookbook(影印版)
<iOS 6编程Cookbook(影印版)> 基本信息 原书名:iOS 6 Programming Cookbook 作者: Vandad Nahavandipoor 出版社:东南大学出版 ...
- iOS 并行编程:NSOperation Queues
1 简介 1.1 功能 Operation Queue也是IOS的一种并行编程技术,类似Dispatch Queue可以帮助用户管理多线程.但是Operation Queue将任务封装在 ...
- IOS网络编程:HTTP
IOS网络编程:HTTP HTTP定义了一种在服务器和客户端之间传递数据的途径. URL定义了一种唯一标示资源在网络中位置的途径. REQUESTS 和 RESPONSES: 客户端先建立一个TCP连 ...
- 深入浅出-iOS函数式编程的实现 && 响应式编程概念
简介 本篇主要回顾一下--iOS函数式编程 && 响应式编程概念 ,如何一步步实现函数式编程的过程,对阅读Masonry && SnapKit源码有一定的帮助. 配图 ...
- [HMLY]11.iOS函数式编程的实现&&响应式编程概念
简介 本篇主要回顾一下--iOS函数式编程 && 响应式编程概念 ,如何一步步实现函数式编程的过程,对阅读Masonry && SnapKit源码有一定的帮助. 作为一 ...
- iOS网络编程笔记——Socket编程
一.什么是Socket通信: Socket是网络上的两个程序,通过一个双向的通信连接,实现数据的交换.这个双向连路的一端称为socket.socket通常用来实现客户方和服务方的连接.socket是T ...
随机推荐
- 安卓中Canvas实现清屏效果
可以在代码里面添加: paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); canvas.drawPaint(paint) ...
- Java系列学习(四)-运算计算
1.运算符 (1)算术运算符 A:+,-,*,/,%,++,-- B:+的用法 [a.加法] [b.正号] [c.字符串连接付] C:/和%的区别 [数据做除法的时候,/取的是商,%取的是余数] D: ...
- jsp: ServletContext
WEB容器在启动时,它会为每个WEB应用程序都创建一个对应的ServletContext对象,它代表当前web应用. ServletConfig对象中维护了ServletContext对象的引用,开发 ...
- iOS- Size Class使用教程
1:它引入了一种新的概念,抛弃传统意义上我们适配时所谓的具体宽高尺寸,把屏幕的宽和高分别分成两种情况:Compact-紧凑, Regular-正常(Any-任意,其实就是这2种的组合,所以我没分成3种 ...
- CF615C Running Track
思路: kmp + 二分. 实现: #include <iostream> #include <cstdio> #include <algorithm> #incl ...
- [hihocoder][Offer收割]编程练习赛58
最大的K-偏差排列 每次取可选范围里的最大的数字,如果最左侧的数字还没有使用就直接使用最左侧的数字 #pragma comment(linker, "/STACK:102400000,102 ...
- React-Native WebView动态加载字体
背景 使用react-native构建的iOS/Android双端APP,通过WebView加载本地页面,需要根据服务器提供的字体列表实现下载和动态加载. 本地字体检查 有些字体手机操作系统已经提供了 ...
- struts.xml详解
参考自:http://blog.csdn.net/zz_mm/article/details/5460397 1. 深入Struts2的配置文件 本部分主要介绍struts.xml的常用配置. ...
- 【Android】一个好用的sharedpreferences存储类方法
其实我也不知道sharedpreferences究竟安全不安全,毕竟是android中最简单的存储机制. 如果你手机root了的话,使用MT管理器到data/data/包名/shared_prefs下 ...
- redis环境部署
运维开发技术交流群欢迎大家加入一起学习(QQ:722381733) 一.Redis服务介绍: redis简单来讲就是一个数据库,一个用来存储缓存的数据库容器,主要是让项目数据能写进缓存,为用户提搞更舒 ...