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 ...
随机推荐
- Linux命令(005) -- kill、pkill和killall的比较
kill命令用来“杀掉”指定进程PID的进程.终止一个前台进程可以使用Ctrl+C,终止一个后台进程就须用kill命令.kill命令是通过向进程发送指定的信号来结束相应进程的.在默认情况下,kill命 ...
- [转]Linux 正则表达式详解
转自:http://www.jb51.net/article/42989.htm 一.linux文本查找命令 在说linux正规表达式之前,还介绍下linux中查找文本文件常用的三个命令: 1.gre ...
- 【转】Linux字符转换命令col
转自:http://www.cnblogs.com/ningvsban/p/3725464.html [root@www ~]# col [-xb]选项与参数:-x :将 tab 键转换成对等的空格键 ...
- C++中 list与vector的区别
引用http://www.cnblogs.com/shijingjing07/p/5587719.html C++ vector和list的区别 1.vector数据结构vector和数组类似,拥有一 ...
- Html基础学习(基于W3school网络教程)
//防止乱码 head中加入 <meta http-equiv="Content-Type" content="text/html; charset=utf-8&q ...
- React Native 环境搭建踩坑
React Native (web Android)环境搭建踩坑(真的是一个艰辛的过程,大概所有坑都被我踩了 官方文档地址 : https://facebook.github.io/react-nat ...
- PHP开发之旅-验证码功能实现
验证码这样的功能可以说是无处不在了,接下来使用php来实现验证码这样的功能,这里我是将验证码实现抽取到一个类中独立开来,那么后面如果再使用到验证码功能,直接引入该类文件并创建该类的实例,就可以使用验证 ...
- 清瘦的记录者: 一个比dbutils更小巧、好用的的持久化工具
https://gitee.com/bitprince/memory 1. 概述 1.1 连接.语句和结果集 从JDBC的规范上看,其对数据访问层有相当简洁的抽象:1.连接(connection) 2 ...
- JS高级——扩展内置对象的方法
基本概念 内置对象有很多,几个比较重要的:Math.String.Date.Array 基本使用 1.内置对象创建出来的对象使用的方法使用的其实都是内置对象的原型对象中的方法 (1)a并没有charA ...
- Android控件的继承关系
1.View,ViewGroup >View: }1.所有高级UI组件都继承View类而实现的 }2.一个View在屏幕上占据一块矩形区域 }3. 负责渲染 }4.负责处理发生的事件 }5.设置 ...