iOS开发------获取系统联系人(AddressBook篇)

AddressBook是Apple提供给我们获取系统联系人的一个很方便类库,与其说方便,其实刚开始还是比较崩溃的,从开发文档来看,它还是偏向于C语言,并且不在ARC的控制之下,虽然在iOS9.0之后会被Contacts.framework替代,但在工作中要对最低版本进行兼容,了解一下这个类库还是很有必要的。这里就介绍一下获取联系人信息的那些方法,对于修改,添加删除等操作,想留在下一篇介绍AddressBookUI这个类库的时候来写一下。

代码GitHub:https://github.com/YRunIntoLove/YAdressBookDemo

获取权限

iOS6.0之后,苹果对于用户隐私就加强了,所有调用系统权限都需要用户授权才可以进行之后的操作,因此在获取通讯录的时候要检测一下有没有权限(这一点在定位,相机等操作上也都看出):

/**
 *  检测权限并作响应的操作
 */
- (void)checkAuthorizationStatus
{
    switch (ABAddressBookGetAuthorizationStatus())
    {
            //存在权限
        case kABAuthorizationStatusAuthorized:
            //获取通讯录
            [self obtainContacts:self.addressBook];
            break;

            //权限未知
        case kABAuthorizationStatusNotDetermined:
            //请求权限
            [self requestAuthorizationStatus];
            break;

            //如果没有权限
        case kABAuthorizationStatusDenied:
        case kABAuthorizationStatusRestricted://需要提示
            //弹窗提醒
            [self showAlertController];
            break;

        default:
            break;
    }
}

请求权限的方法如下:

/**
 *  请求通讯录的权限
 */
- (void)requestAuthorizationStatus
{
    //避免强引用
    __weak typeof(self) copy_self = self;

    ABAddressBookRequestAccessWithCompletion(self.addressBook, ^(bool granted, CFErrorRef error) {

        //权限得到允许
        if (granted == true)
        {
            //主线程获取联系人
            dispatch_async(dispatch_get_main_queue(), ^{

                [copy_self obtainContacts:self.addressBook];

            });
        }
    });
}

请求联系人列表

为Demo中是楼主自行构建的Model,因此代码就显得简略了好多,后面会附上CFRecord转模型的代码:

/**
 *  获取通讯录中的联系人
 */
- (void)obtainContacts:(ABAddressBookRef)addressBook
{
    //按照添加时间请求所有的联系人
    CFArrayRef contants = ABAddressBookCopyArrayOfAllPeople(addressBook);

    //按照排序规则请求所有的联系人
//    ABRecordRef recordRef = ABAddressBookCopyDefaultSource(addressBook);
      //这里的firstName是按照姓名属性中的firstName来排序的,并不是按照全称来排序
//    CFArrayRef contants = ABAddressBookCopyArrayOfAllPeopleInSourceWithSortOrdering(addressBook, recordRef, kABPersonSortByFirstName);

    //存放所有联系人的数组
    NSMutableArray <YContactObject *> * contacts = [NSMutableArray arrayWithCapacity:0];

    //遍历获取所有的数据
    for (NSInteger i = 0; i < CFArrayGetCount(contants); i++)
    {
        //获得People对象
        ABRecordRef recordRef = CFArrayGetValueAtIndex(contants, i);

        //获得contact对象
        YContactObject * contactObject = [YContactObjectManager contantObject:recordRef];

        //添加对象
        [contacts addObject:contactObject];
    }

    //释放资源,因为不在ARC下,retain或者copy之后记得release
    CFRelease(contants);

    //进行回调赋值
    ContactDidObatinBlock copyBlock  = self.contactsDidObtainBlockHandle;

    //进行数据回调
    copyBlock([NSArray arrayWithArray:contacts]);
}

获取联系人的姓名属性

为了让代码可读性更好一点,在进行转型的时候写了如下方法,是为了方便将CFStringRef通过桥接__bridge转型成NSString对象:

/**
 *  根据属性key获得NSString
 *
 *  @param property 属性key
 */
+ (NSString *)contactProperty:(ABPropertyID) property
{
    return (__bridge NSString *)(ABRecordCopyValue(self.recordRef, property));
}

获取姓名相关属性方法如下:

/**
 *  获得姓名的相关属性
 */
+ (YContactNameObject *)contactNameProperty
{
    //初始化对象
    YContactNameObject * nameObject = [[YContactNameObject alloc]init];

    nameObject.givenName = [self contactProperty:kABPersonFirstNameProperty];                   //名字
    nameObject.familyName = [self contactProperty:kABPersonLastNameProperty];                   //姓氏
    nameObject.middleName = [self contactProperty:kABPersonMiddleNameProperty];                 //名字中的信仰名称(比如Jane·K·Frank中的K)
    nameObject.namePrefix = [self contactProperty:kABPersonPrefixProperty];                     //名字前缀
    nameObject.nameSuffix = [self contactProperty:kABPersonSuffixProperty];                     //名字后缀
    nameObject.nickName = [self contactProperty:kABPersonNicknameProperty];                     //名字昵称
    nameObject.phoneticGivenName = [self contactProperty:kABPersonFirstNamePhoneticProperty];   //名字的拼音音标
    nameObject.phoneticFamilyName = [self contactProperty:kABPersonLastNamePhoneticProperty];   //姓氏的拼音音标
    nameObject.phoneticMiddleName = [self contactProperty:kABPersonMiddleNamePhoneticProperty]; //英文信仰缩写字母的拼音音标

    return nameObject;
}

获取联系人的类型

/**
 *  获得联系人类型信息
 */
+ (YContactType)contactTypeProperty
{
    //获得类型属性
    CFNumberRef typeIndex = ABRecordCopyValue(self.recordRef, kABPersonKindProperty);

    //表示是公司联系人
    if (CFNumberCompare(typeIndex, kABPersonKindOrganization, nil) == kCFCompareEqualTo)
    {
        //释放资源
        CFRelease(typeIndex);

        return YContactTypeOrigination;
    }

    return YContactTypePerson;
}

获取联系人的头像图片

/**
 *  获得联系人的头像图片
 */
+ (UIImage *)contactHeadImagePropery
{
    //首先判断是否存在头像
    if (ABPersonHasImageData(self.recordRef) == false)//没有头像,返回nil
    {
        return nil;
    }

    //开始获得头像信息
    NSData * imageData = (__bridge NSData *)(ABPersonCopyImageData(self.recordRef));

    //获得头像原图
//    NSData * imageData = CFBridgingRelease(ABPersonCopyImageDataWithFormat(self.recordRef, kABPersonImageFormatOriginalSize));

    return [UIImage imageWithData:imageData];
}

获取联系人的电话信息

/**
 *  获得电话号码对象数组
 */
+ (NSArray <YContactPhoneObject *> *)contactPhoneProperty
{
    //外传数组
    NSMutableArray <YContactPhoneObject *> * phones = [NSMutableArray arrayWithCapacity:0];

    //获得电话号码的多值属性
    ABMultiValueRef values = ABRecordCopyValue(self.recordRef, kABPersonPhoneProperty);

    for (NSInteger i = 0; i < ABMultiValueGetCount(values); i++)
    {
        YContactPhoneObject * phoneObject = [[YContactPhoneObject alloc]init];

        //开始赋值
        phoneObject.phoneTitle = (__bridge NSString *)ABAddressBookCopyLocalizedLabel(ABMultiValueCopyLabelAtIndex(values, i)); //电话描述(如住宅、工作..)
        phoneObject.phoneNumber = (__bridge NSString *)ABMultiValueCopyValueAtIndex(values, i);                                 //电话号码

        //添加数据
        [phones addObject:phoneObject];
    }

    //释放资源
    CFRelease(values);

    return [NSArray arrayWithArray:phones];
}

获取联系人的工作信息

/**
 *  获得工作的相关属性
 */
+ (YContactJobObject *)contactJobProperty
{
    YContactJobObject * jobObject = [[ YContactJobObject alloc]init];

    jobObject.organizationName = [self contactProperty:kABPersonOrganizationProperty]; //公司(组织)名称
    jobObject.departmentName = [self contactProperty:kABPersonDepartmentProperty];     //部门
    jobObject.jobTitle = [self contactProperty:kABPersonJobTitleProperty];             //职位

    return jobObject;
}

获取联系人的邮件信息

/**
 *  获得Email对象的数组
 */
+ (NSArray <YContactEmailObject *> *)contactEmailProperty
{
    //外传数组
    NSMutableArray <YContactEmailObject *> * emails = [NSMutableArray arrayWithCapacity:0];

    //获取多值属性
    ABMultiValueRef values = ABRecordCopyValue(self.recordRef, kABPersonEmailProperty);

    //遍历添加
    for (NSInteger i = 0; i < ABMultiValueGetCount(values); i++)
    {
        YContactEmailObject * emailObject = [[YContactEmailObject alloc]init];

        emailObject.emailTitle = (__bridge NSString *)(ABAddressBookCopyLocalizedLabel(ABMultiValueCopyLabelAtIndex(values, i)));  //邮件描述
        emailObject.emailAddress = (__bridge NSString *)(ABMultiValueCopyValueAtIndex(values, i));                                 //邮件地址
        //添加
        [emails addObject:emailObject];
    }

    //释放资源
    CFRelease(values);

    return [NSArray arrayWithArray:emails];
}

获取联系人的地址信息

/**
 *  获得Address对象的数组
 */
+ (NSArray <YContactAddressObject *> *)contactAddressProperty
{
    //外传数组
    NSMutableArray <YContactAddressObject *> * addresses = [NSMutableArray arrayWithCapacity:0];

    //获取多指属性
    ABMultiValueRef values = ABRecordCopyValue(self.recordRef, kABPersonAddressProperty);

    //遍历添加
    for (NSInteger i = 0; i < ABMultiValueGetCount(values); i++)
    {
        YContactAddressObject * addressObject = [[YContactAddressObject alloc]init];

        //赋值
        addressObject.addressTitle = (__bridge NSString *)ABAddressBookCopyLocalizedLabel((ABMultiValueCopyLabelAtIndex(values, i)));                    //地址标签

        //获得属性字典
        NSDictionary * dictionary = (__bridge NSDictionary *)ABMultiValueCopyValueAtIndex(values, i);

        //开始赋值
        addressObject.country = [dictionary valueForKey:(__bridge NSString *)kABPersonAddressCountryKey];               //国家
        addressObject.city = [dictionary valueForKey:(__bridge NSString *)kABPersonAddressCityKey];                     //城市
        addressObject.state = [dictionary valueForKey:(__bridge NSString *)kABPersonAddressStateKey];                   //省(州)
        addressObject.street = [dictionary valueForKey:(__bridge NSString *)kABPersonAddressStreetKey];                 //街道
        addressObject.postalCode = [dictionary valueForKey:(__bridge NSString *)kABPersonAddressZIPKey];                //邮编
        addressObject.ISOCountryCode = [dictionary valueForKey:(__bridge NSString *)kABPersonAddressCountryCodeKey];    //ISO国家编号

        //添加数据
        [addresses addObject:addressObject];
    }

    //释放资源
    CFRelease(values);

    return [NSArray arrayWithArray:addresses];

}

获取联系人的生日信息

/**
 *  根据属性key获得NSDate
 *
 *  @param property 属性key
 *
 *  @return NSDate对象
 */
+ (NSDate *)contactDateProperty:(ABPropertyID) property
{
    return (__bridge NSDate *)(ABRecordCopyValue(self.recordRef, property));
}

/**
 *  获得生日的相关属性
 */
+ (YContactBrithdayObject *)contactBrithdayProperty
{
    //实例化对象
    YContactBrithdayObject * brithdayObject = [[YContactBrithdayObject alloc]init];

    //生日的日历
    brithdayObject.brithdayDate = [self contactDateProperty:kABPersonBirthdayProperty];         //生日的时间对象

    //获得农历日历属性的字典
    NSDictionary * brithdayDictionary = (__bridge NSDictionary *)(ABRecordCopyValue(self.recordRef, kABPersonAlternateBirthdayProperty));

    //农历日历的属性,设置为农历属性的时候,此字典存在数值
    if (brithdayDictionary != nil)
    {

        brithdayObject.calendar = [brithdayDictionary valueForKey:@"calendar"];                                 //农历生日的标志位,比如“chinese”

        //农历生日的相关存储属性
        brithdayObject.era = [(NSNumber *)[brithdayDictionary valueForKey:@"era"] integerValue];                //纪元,六十组干支纪年的索引数,比如12年为壬辰年,为循环的29,此数字为29
        brithdayObject.year = [(NSNumber *)[brithdayDictionary valueForKey:@"year"] integerValue];              //年份

        brithdayObject.month = [(NSNumber *)[brithdayDictionary valueForKey:@"month"] integerValue];            //月份
        brithdayObject.leapMonth = [(NSNumber *)[brithdayDictionary valueForKey:@"isLeapMonth"] boolValue];     //是否是闰月
        brithdayObject.day = [(NSNumber *)[brithdayDictionary valueForKey:@"day"] integerValue];                //日期

    }

    //返回对象
    return brithdayObject;
}

获取联系人的即时通信信息

/**
 *  获得即时通信账号相关信息
 */
+ (NSArray <YContactInstantMessageObject *> *)contactMessageProperty
{
    //存放数组
    NSMutableArray <YContactInstantMessageObject *> * instantMessages = [NSMutableArray arrayWithCapacity:0];

    //获取数据字典
    ABMultiValueRef messages = ABRecordCopyValue(self.recordRef, kABPersonInstantMessageProperty);

    //遍历获取值
    for (NSInteger i = 0; i < ABMultiValueGetCount(messages); i++)
    {
        //获取属性字典
        NSDictionary * messageDictionary = CFBridgingRelease(ABMultiValueCopyValueAtIndex(messages, i));

        //实例化
        YContactInstantMessageObject * instantMessageObject = [[YContactInstantMessageObject alloc]init];

        instantMessageObject.service = [messageDictionary valueForKey:@"service"];          //服务名称(如QQ)
        instantMessageObject.userName = [messageDictionary valueForKey:@"username"];        //服务账号(如QQ号)

        //添加
        [instantMessages addObject:instantMessageObject];
    }

    return [NSArray arrayWithArray:instantMessages];
}

获得联系人的关联人信息

/**
 *  获得联系人的关联人信息
 */
+ (NSArray <YContactRelatedNamesObject *> *)contactRelatedNamesProperty
{
    //存放数组
    NSMutableArray <YContactRelatedNamesObject *> * relatedNames = [NSMutableArray arrayWithCapacity:0];

    //获得多值属性
    ABMultiValueRef names = ABRecordCopyValue(self.recordRef, kABPersonRelatedNamesProperty);

    //遍历赋值
    for (NSInteger i = 0; i < ABMultiValueGetCount(names); i++)
    {
        //初始化
        YContactRelatedNamesObject * relatedName = [[YContactRelatedNamesObject alloc]init];

        //赋值
        relatedName.relatedTitle = CFBridgingRelease(ABAddressBookCopyLocalizedLabel(ABMultiValueCopyLabelAtIndex(names, i))); //关联的标签(如friend)
        relatedName.relatedName = CFBridgingRelease(ABMultiValueCopyValueAtIndex(names, i));                                    //关联的名称(如联系人姓名)

        //添加
        [relatedNames addObject:relatedName];
    }

    return [NSArray arrayWithArray:relatedNames];
}

获取联系人的社交简介信息

/**
 *  获得联系人的社交简介信息
 */
+ (NSArray <YContactSocialProfileObject *> *)contactSocialProfilesProperty
{
    //外传数组
    NSMutableArray <YContactSocialProfileObject *> * socialProfiles = [NSMutableArray arrayWithCapacity:0];

    //获得多值属性
    ABMultiValueRef profiles = ABRecordCopyValue(self.recordRef, kABPersonSocialProfileProperty);

    //遍历取值
    for (NSInteger i = 0; i < ABMultiValueGetCount(profiles); i++)
    {
        //初始化对象
        YContactSocialProfileObject * socialProfileObject = [[YContactSocialProfileObject alloc]init];

        //获取属性值
        NSDictionary * profileDictionary = CFBridgingRelease(ABMultiValueCopyValueAtIndex(profiles, i));

        //开始赋值
        socialProfileObject.socialProfileTitle = [profileDictionary valueForKey:@"service"];    //社交简介(如sinaweibo)
        socialProfileObject.socialProFileAccount = [profileDictionary valueForKey:@"username"]; //社交地址(如123456)
        socialProfileObject.socialProFileUrl = [profileDictionary valueForKey:@"url"];          //社交链接的地址(按照上面两项自动为http://weibo.com/n/123456)

        //添加
        [socialProfiles addObject:socialProfileObject];
    }
    return [NSArray arrayWithArray:socialProfiles];
}

获取联系人的备注信息

//备注
contactObject.note = [self contactProperty:kABPersonNoteProperty];               

获取联系人的创建时间

//创建时间
contactObject.creationDate = [self contactDateProperty:kABPersonCreationDateProperty];

获取联系人的最近修改时间

//最近一次修改的时间
contactObject.modificationDate = [self contactDateProperty:kABPersonModificationDateProperty];

接收外界通讯录发生变化的方法

在初始化AddressBook的时候为它注册一个通知

//创建一个AddressBook
self.addressBook = ABAddressBookCreate();

/**
 *  注册通讯录变动的回调
 *
 *  @param self.addressBook          注册的addressBook
 *  @param addressBookChangeCallBack 变动之后进行的回调方法
 *  @param void                      传参,这里是将自己作为参数传到方法中,
 *  将自己传过去的时候,一定要用__bridge_retained一下,如果不retained,会发生内存泄露,计数器不正确,导致程序崩溃
 */
ABAddressBookRegisterExternalChangeCallback(self.addressBook,  addressBookChangeCallBack, (__bridge_retained void *)(self));

在外面自己写回调的方法,这个方法是外界的通讯录发生增删改查之后,再次回到此App的时候才会触发的方法

void addressBookChangeCallBack(ABAddressBookRef addressBook, CFDictionaryRef info, void *context)
{
    //coding when addressBook did changed
    NSLog(@"通讯录发生变化啦");

    //初始化对象,这里是将参数转成对象的方法
    YContactsManager * contactManager = CFBridgingRelease(context);

}
时间: 2024-10-20 16:46:53

iOS开发------获取系统联系人(AddressBook篇)的相关文章

iOS开发,系统自带表情的获取

//将数字转为 #define EMOJI_CODE_TO_SYMBOL(x) ((((0x808080F0 | (x & 0x3F000) >> 4) | (x & 0xFC0) << 10) | (x & 0x1C0000) << 18) | (x & 0x3F) << 24); - (void)viewDidLoad { [super viewDidLoad]; //单独调用 int sym = EMOJI_CODE_T

iOS开发之系统通讯录

@iOS调用操作通讯录所用的库文件 AddressBook.framework AddressBookUI.framework #import "HMTMainViewController.h" #import <AddressBook/AddressBook.h> #import <AddressBookUI/AddressBookUI.h> @interface HMTMainViewController ()<ABPeoplePickerNaviga

iOS开发——完整项目实战OC篇&amp;百思不得姐第四天

iOS开发——完整项目实战OC篇&百思不得姐第四天 上午 一:自定义按钮使用九宫格布局 二:控件不能点击 三:获取用户点击了那个按钮 四:调整按钮内部控件的位置:主流->上下 五:不能直接使用self.navigationController中或者View中获取导航控制器 方法一: 方法二: 六:布局取整 1 // 总行数 2 3 // NSUInteger rows = sqaures.count / maxCols; 4 5 // if (sqaures.count % maxCols)

iOS开发利用系统推送Notifaction和轮询实现简单聊天系统

话不多说,先看一下做好的聊天软件界面: 首先在StoryBoard里拖了一个UItableView和一个view用来输入文字或者语音,右边的按钮用来切换文字和语音: 聊天里有三种id: orderID :聊天id messageID :每条消息的ID sessionID :每个订单的会话ID,如果为空通过orderID请求. 然后在viewDidLoad里做一些界面上的操作和一些初始化的操作: 1.设置一下tableview的headView 2.初始化录音.用户头像.获取订单详情 <stron

获取系统联系人&&添加系统联系人

联系人在这个包下 contacts2.db数据库 查询所有的联系人; 需要读写contact权限,注意Uri   content是小写的 找这个错误找了一个小时,汗-  -!! 这个程序只是添加个按钮. package com.example.getcontacts; import android.app.Activity; import android.content.ContentResolver; import android.database.Cursor; import android

iOS开发 点菜系统 使用UIPickerView

利用UIPickerView实现一个简单的点菜界面,如下图所示.源码地址:https://github.com/xiaoLong1010/iOSAppDemo.git UIPickerView有两个协议UIPickerViewDataSource,UIPickerViewDelegate,它们为UIPickeView提供数据和代理.UIPickeView的三个component分别代表fruit,main,drink,选中某一行,菜名在下面显示.最上面的随机按钮,则实现随机点菜功能. 1.vie

iOS开发- 获取精确剩余电量

[UIDevice currentDevice].batteryMonitoringEnabled = YES; double deviceLevel = [UIDevice currentDevice].batteryLevel; 获取当前剩余电量, 我们通常采用上述方法.这也是苹果官方文档提供的. 它返回的是0.00-1.00之间的浮点值.  另外, -1.00表示模拟器. 貌似这个方法不错, 也很简单. 但是仔细观察它的返回值, 我们可以发现. 它是以0.05递变的. 折算成100% 也就

iOS开发 - 获取真机沙盒数据

今天要获取之前真机测试时写入沙盒的数据, 本来以为挺麻烦的. 后来捣腾了一下, 才知道原来这么简单... 下面直接看具体步骤. 前提: 真机已经通过USB和你的电脑连接上了! 1.进入Organizer 2.选择你的应用. 并导出数据.(点击Download) 3.保存数据到相应位置.(点击Save) 4.打开, 查看数据. 保存完毕后, 你后发现一个这样的文件. 选中它, 右键---->显示包内容. 然后进入------->AppData ------>Documents. 即可看到你

IOS开发调用系统相机和打开闪光灯

IOS开发调用系统相机和打开闪光灯      今天给大家分享一下如何调用iphone的拍照功能和打开闪光灯,有些代码我也不太理解,很多是在网上借鉴其他人的.IOS有两种的拍照和视频的方 式:1.直接使用UIImagePickerController,这个类提供了一个简单便捷的拍照与选择图片库里图片的功能.2.另一种是通过 AVFoundation.framework框架完全自定义拍照的界面和选择图片库界面.我只做了第一种,就先给大家介绍第一种做法: 一.首先调用接口前,我们需要先判断当前设备是否