iOS開發之AddressBook框架詳解

iOS開發之AddressBook框架詳解

一、寫在前面

    首先,AddressBook框架是一個已經過時的框架,iOS9之後官方提供了Contacts框架來進行用戶通訊錄相關操作。儘管如此,AddressBook框架依然是一個非常優雅並且使用方便的通訊錄幫助庫。本篇博客只要總結AddressBook框架的相關使用方法。

    在AddressBook框架中,兩個最重要的數據模型爲ABAddressbookRef與ABRecordRef。前者我們可以理解爲通訊錄的抽象對象,用它來具體操作通訊錄的行爲,後者可以理解爲通訊錄中記錄的抽象對象,其中封裝了聯繫人的相關信息。如下圖所示:

二、關於用戶權限申請

    在應用程序內,若需要使用用戶的通訊錄權限需要徵得用戶的同意(畢竟通訊錄屬於用戶隱私)。因此,在使用之前,開發者首先需要進行權限的申請,首先,需要在info.plist文件中添加如下鍵:

Privacy - Contacts Usage Description

使用如下代碼進行使用權限的申請:

//獲取用戶授權狀態
ABAuthorizationStatus status = ABAddressBookGetAuthorizationStatus();
//如果尚未獲取過授權 進行授權申請
if (status==kABAuthorizationStatusNotDetermined) {
    //創建通訊錄對象 這個方法中第1個參數爲預留參數 傳NULL 即可 第2個參數可以傳一個CFErrorRef的指針
    ABAddressBookRef addressBookRef = ABAddressBookCreateWithOptions(NULL, NULL);
    //請求授權
    ABAddressBookRequestAccessWithCompletion(addressBookRef, ^(bool granted, CFErrorRef error) {
        if (granted) {//請求授權頁面用戶同意授權
            //可以進行使用
        }
        //釋放內存
        CFRelease(addressBookRef);
    });
}

ABAuthorizationStatus是授權狀態的枚舉,意義如下:

typedef CF_ENUM(CFIndex, ABAuthorizationStatus) {
    kABAuthorizationStatusNotDetermined = 0,    // 尚未申請過授權
    kABAuthorizationStatusRestricted,           // 授權被限制 無法使用
    kABAuthorizationStatusDenied,               // 用戶拒絕授權
    kABAuthorizationStatusAuthorized            // 已經授權
}

三、獲取基礎的通訊錄信息

    下面代碼演示瞭如何獲取基礎的通訊錄聯繫人信息:

        //獲取通訊錄
        ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, NULL);
        //獲取聯繫人數量
        CFIndex personCount = ABAddressBookGetPersonCount(addressBook);
        //拿到所有聯繫人
        CFArrayRef peopleArray = ABAddressBookCopyArrayOfAllPeople(addressBook);
        for (int i = 0; i < personCount; i++) {
            //獲取記錄
            ABRecordRef person = CFArrayGetValueAtIndex(peopleArray, i);
            //拿到姓名
            //姓 需要轉換成NSString類型
            NSString *lastNameValue = (__bridge_transfer NSString *)ABRecordCopyValue(person, kABPersonLastNameProperty);
            //名
            NSString *firstNameValue = (__bridge_transfer NSString *)ABRecordCopyValue(person, kABPersonFirstNameProperty);
            NSLog(@"%@:%@",lastNameValue,firstNameValue);
            //拿到電話 電話可能有多個
            ABMultiValueRef phones = ABRecordCopyValue(person, kABPersonPhoneProperty);
            //解析電話數據
            CFIndex phoneCount = ABMultiValueGetCount(phones);
            for (int j = 0; j < phoneCount ; j++) {
                //電話標籤本地化(例如是住宅,工作等)
                NSString *phoneLabel = (__bridge_transfer NSString *)ABAddressBookCopyLocalizedLabel(ABMultiValueCopyLabelAtIndex(phones, j));
                //拿到標籤下對應的電話號碼
                NSString *phoneValue = (__bridge_transfer NSString *)ABMultiValueCopyValueAtIndex(phones, j);
                NSLog(@"%@:%@",phoneLabel,phoneValue);
            }
            CFRelease(phones);
            
            //郵箱 可能多個
            ABMultiValueRef emails = ABRecordCopyValue(person, kABPersonEmailProperty);
            CFIndex emailCount = ABMultiValueGetCount(emails);
            for (int k = 0; k < emailCount; k++) {
                NSString *emailLabel = (__bridge_transfer NSString *)ABAddressBookCopyLocalizedLabel(ABMultiValueCopyLabelAtIndex(emails, k));
                NSString *emailValue = (__bridge_transfer NSString *)ABMultiValueCopyValueAtIndex(emails, k);
                NSLog(@"%@:%@",emailLabel,emailValue);
            }
            NSLog(@"==============");
            CFRelease(emails);
        }
        CFRelease(addressBook);
        CFRelease(peopleArray);

打印信息如下:

關於可獲取到的聯繫人屬性,鍵值列舉如下:

//名
kABPersonFirstNameProperty
//姓
kABPersonLastNameProperty
//中間名
kABPersonMiddleNameProperty
//前綴 用戶在存儲聯繫人時 可以添加自定義的前綴 例如 女士 男士等等
kABPersonPrefixProperty
//後綴
kABPersonSuffixProperty
//暱稱
kABPersonNicknameProperty
//姓發音說明字段 用戶自定義的
kABPersonFirstNamePhoneticProperty
//名發音說明字段 用戶自定義的
kABPersonLastNamePhoneticProperty
//中間名發音說明字段 用戶自定義的
kABPersonMiddleNamePhoneticProperty
//公司名
kABPersonOrganizationProperty
//部門名
kABPersonDepartmentProperty
//頭銜
kABPersonJobTitleProperty
//電子郵件信息 返回一組 需要手動解析
kABPersonEmailProperty
//返回生日信息 日期對象
kABPersonBirthdayProperty
//筆記信息
kABPersonNoteProperty
//記錄的創建日期
kABPersonCreationDateProperty
//記錄的最後修改日期
kABPersonModificationDateProperty
//地址信息 返回 一組
/*
例如:
ABMultiValueRef address = ABRecordCopyValue(person, kABPersonAddressProperty);
     for (int j=0; j<ABMultiValueGetCount(address); j++) {
         //地址類型
         NSString *type = (__bridge NSString *)(ABMultiValueCopyLabelAtIndex(address, j));
         NSDictionary * temDic = (__bridge NSDictionary *)(ABMultiValueCopyValueAtIndex(address, j));
        //地址字符串,可以按需求格式化
        NSString * adress = [NSString stringWithFormat:@"國家:%@\n省:%@\n市:%@\n街道:%@\n郵編:%@",[temDic valueForKey:(NSString*)kABPersonAddressCountryKey],[temDic valueForKey:(NSString*)kABPersonAddressStateKey],[temDic valueForKey:(NSString*)kABPersonAddressCityKey],[temDic valueForKey:(NSString*)kABPersonAddressStreetKey],[temDic valueForKey:(NSString*)kABPersonAddressZIPKey]];
     }
*/
kABPersonAddressProperty
//地址字典中的街道信息鍵
kABPersonAddressStreetKey
//地址字典中的城市信息鍵
kABPersonAddressCityKey
//地址字典中的地區信息鍵
kABPersonAddressStateKey
//地址字典中的壓縮碼信息鍵
kABPersonAddressZIPKey
//地址字典中的國家信息鍵
kABPersonAddressCountryKey
//地址字典中的國家編碼信息鍵
kABPersonAddressCountryCodeKey
//獲取 一組 紀念日日期 
kABPersonDateProperty
//從具體的日期實體中獲取紀念日 標籤
kABPersonAnniversaryLabel
//獲取一組電話號碼
kABPersonPhoneProperty
//下面這些對應電話類型
kABPersonPhoneMobileLabel
kABPersonPhoneIPhoneLabel
kABPersonPhoneMainLabel
kABPersonPhoneHomeFAXLabel
kABPersonPhoneWorkFAXLabel
kABPersonPhoneOtherFAXLabel
kABPersonPhonePagerLabel
//獲取社交相關信息
kABPersonInstantMessageProperty
//下面這些對應社交平臺
kABPersonInstantMessageServiceKey         
kABPersonInstantMessageServiceYahoo
kABPersonInstantMessageServiceJabber
kABPersonInstantMessageServiceMSN
kABPersonInstantMessageServiceICQ
kABPersonInstantMessageServiceAIM
kABPersonInstantMessageServiceQQ 
kABPersonInstantMessageServiceGoogleTalk
kABPersonInstantMessageServiceSkype
kABPersonInstantMessageServiceFacebook
kABPersonInstantMessageServiceGaduGadu
//社交用戶名
kABPersonInstantMessageUsernameKey
//獲取一組url
kABPersonURLProperty
//url相關標籤
kABPersonHomePageLabel
//關聯信息
kABPersonRelatedNamesProperty
//關聯信息相關的標籤
kABPersonFatherLabel                           
kABPersonMotherLabel                           
kABPersonParentLabel
kABPersonBrotherLabel                       
kABPersonSisterLabel                     
kABPersonChildLabel
kABPersonFriendLabel
kABPersonSpouseLabel 
kABPersonPartnerLabel 
kABPersonAssistantLabel
kABPersonManagerLabel
//獲取社交賬戶相關
kABPersonSocialProfileProperty
//社交賬戶相關key
kABPersonSocialProfileURLKey
kABPersonSocialProfileServiceKey
kABPersonSocialProfileUsernameKey
kABPersonSocialProfileUserIdentifierKey
kABPersonSocialProfileServiceTwitter
kABPersonSocialProfileServiceSinaWeibo
kABPersonSocialProfileServiceGameCenter
kABPersonSocialProfileServiceFacebook
kABPersonSocialProfileServiceMyspace
kABPersonSocialProfileServiceLinkedIn
kABPersonSocialProfileServiceFlickr
//週期性日期信息
kABPersonAlternateBirthdayProperty
//週期性日期相關鍵
kABPersonAlternateBirthdayCalendarIdentifierKey
kABPersonAlternateBirthdayEraKey
kABPersonAlternateBirthdayYearKey
kABPersonAlternateBirthdayMonthKey
kABPersonAlternateBirthdayIsLeapMonthKey
kABPersonAlternateBirthdayDayKey

四、關於ABMultiValueRef

    如上所述,我們在獲取聯繫人相關信息時,很多場景都會獲取一組,例如對於電話號碼,地址,郵箱這類的數據。在AddressBook框架中,這一組數據被封裝爲ABMultiValueRef對象。對於ABMultiValueRef對象,有如下方法可以對其進行處理:

//獲取內部封裝值的類型
/*
enum {
    kABInvalidPropertyType         = 0x0,                                           // 無效
    kABStringPropertyType          = 0x1,                                           // 字符串
    kABIntegerPropertyType         = 0x2,                                           // 整數
    kABRealPropertyType            = 0x3,                                           // 屬性
    kABDateTimePropertyType        = 0x4,                                           // 時間
    kABDictionaryPropertyType      = 0x5,                                           // 字典
    kABMultiStringPropertyType     = kABMultiValueMask | kABStringPropertyType,     // 聚合字符串
    kABMultiIntegerPropertyType    = kABMultiValueMask | kABIntegerPropertyType,    // 聚合整型
    kABMultiRealPropertyType       = kABMultiValueMask | kABRealPropertyType,       // 聚合屬性
    kABMultiDateTimePropertyType   = kABMultiValueMask | kABDateTimePropertyType,   // 聚合時間
    kABMultiDictionaryPropertyType = kABMultiValueMask | kABDictionaryPropertyType, // 聚合字典
};
*/
ABPropertyType ABMultiValueGetPropertyType(ABMultiValueRef multiValue)
//獲取其中封裝的值的個數
CFIndex ABMultiValueGetCount(ABMultiValueRef multiValue)
//根據索引獲取值
ABMultiValueCopyValueAtIndex(ABMultiValueRef multiValue, CFIndex index)
//獲取所有的值 組成數組
CFArrayRef ABMultiValueCopyArrayOfAllValues(ABMultiValueRef multiValue)
//根據索引獲取標籤
CFStringRef ABMultiValueCopyLabelAtIndex(ABMultiValueRef multiValue, CFIndex index)
//根據ID獲取值
ABMultiValueIdentifier ABMultiValueGetIdentifierAtIndex(ABMultiValueRef multiValue, CFIndex index)
//根據ID 獲取索引
CFIndex ABMultiValueGetIndexForIdentifier(ABMultiValueRef multiValue, ABMultiValueIdentifier identifier)
//獲取第一個值
CFIndex ABMultiValueGetFirstIndexOfValue(ABMultiValueRef multiValue, CFTypeRef value)
//下面這些與寫聯繫人信息相關
//創建一個可變的數據對象 
ABMutableMultiValueRef ABMultiValueCreateMutable(ABPropertyType type)
//爲某個標籤添加值
bool ABMultiValueAddValueAndLabel(ABMutableMultiValueRef multiValue, CFTypeRef value, CFStringRef label, ABMultiValueIdentifier *outIdentifier)
//在某個索引處插入 標籤和值
bool ABMultiValueInsertValueAndLabelAtIndex(ABMutableMultiValueRef multiValue, CFTypeRef value, CFStringRef label, CFIndex index, ABMultiValueIdentifier *outIdentifier)
//刪除某個索引處的標籤和值
bool ABMultiValueRemoveValueAndLabelAtIndex(ABMutableMultiValueRef multiValue, CFIndex index)
//替換某個索引處的值
bool ABMultiValueReplaceValueAtIndex(ABMutableMultiValueRef multiValue, CFTypeRef value, CFIndex index)
//替換某個索引處的標籤
bool ABMultiValueReplaceLabelAtIndex(ABMutableMultiValueRef multiValue, CFStringRef label, CFIndex index)

五、ABRecordRef對象

    ABRecordRef雖然很多時候,我們可以把它理解爲聯繫人對象,但是其實並不正確,實際上它是一個抽象的記錄對象,在AddressBook框架中有3種類型的ABRecordRef:

enum {
    kABPersonType = 0, //聯繫人類型
    kABGroupType  = 1, //組類型
    kABSourceType = 2  //資源類型
};

可以操作ABRecordRef的方法非常簡單,無非讀與寫,如下:

//獲取記錄類型
ABRecordType ABRecordGetRecordType(ABRecordRef record);
//獲取記錄中的數據
CFTypeRef ABRecordCopyValue(ABRecordRef record, ABPropertyID property);
//設置記錄中的數據
bool ABRecordSetValue(ABRecordRef record, ABPropertyID property, CFTypeRef value, CFErrorRef* error);
//刪除記錄中的數據
bool ABRecordRemoveValue(ABRecordRef record, ABPropertyID property, CFErrorRef* error);

六、聯繫人組

    在iOS系統的聯繫人應用中,我們可以對聯繫人進行分組,如下圖所示:

AddressBook框架中的如下方法與聯繫人組操作相關:

//創建一個聯繫人組記錄
ABRecordRef ABGroupCreate(void);
//在指定的資源中創建
ABRecordRef ABGroupCreateInSource(ABRecordRef source);
//獲取資源
ABRecordRef ABGroupCopySource(ABRecordRef group);
//獲取組中的所有成員
CFArrayRef ABGroupCopyArrayOfAllMembers(ABRecordRef group);
//根據指定的排序方法獲取組中所有成員
CFArrayRef ABGroupCopyArrayOfAllMembersWithSortOrdering(ABRecordRef group, ABPersonSortOrdering sortOrdering);
//向組中添加成員
bool ABGroupAddMember(ABRecordRef group, ABRecordRef person, CFErrorRef* error);
//刪除組中的成員
bool ABGroupRemoveMember(ABRecordRef group, ABRecordRef member, CFErrorRef* error);
//根據某條記錄獲取組
ABRecordRef ABAddressBookGetGroupWithRecordID(ABAddressBookRef addressBook, ABRecordID recordID);
//獲取通訊錄中所有組的個數
CFIndex ABAddressBookGetGroupCount(ABAddressBookRef addressBook);
//獲取通訊錄中所有組
CFArrayRef ABAddressBookCopyArrayOfAllGroups(ABAddressBookRef addressBook);
CFArrayRef ABAddressBookCopyArrayOfAllGroupsInSource(ABAddressBookRef addressBook, ABRecordRef source);

七、重中之重——ABAddressBookRef對象

    前面介紹了許多操作聯繫人,操作組的方法,所有這些操作的基礎都是基於一個通訊錄對象ABAddressBookRef的。除了最前面演示的申請權限的相關方法,如下列舉了與ABAddressBookRef相關的其他常用函數:

//存儲通訊錄
bool ABAddressBookSave(ABAddressBookRef addressBook, CFErrorRef* error);
//獲取通訊錄是否有未保存的更改
bool ABAddressBookHasUnsavedChanges(ABAddressBookRef addressBook);
//向通訊錄中添加一條記錄
bool ABAddressBookAddRecord(ABAddressBookRef addressBook, ABRecordRef record, CFErrorRef* error);
//移除通訊錄中的一條記錄
bool ABAddressBookRemoveRecord(ABAddressBookRef addressBook, ABRecordRef record, CFErrorRef* error);
//註冊通訊錄發生變化時的外部監聽
void ABAddressBookRegisterExternalChangeCallback(ABAddressBookRef addressBook, ABExternalChangeCallback callback, void *context);
//移除通訊錄發生變化時的外部監聽
void ABAddressBookUnregisterExternalChangeCallback(ABAddressBookRef addressBook, ABExternalChangeCallback callback, void *context);
//將未保存的更改重置
void ABAddressBookRevert(ABAddressBookRef addressBook);
//工具方法,進行標籤的本地化轉換
CFStringRef ABAddressBookCopyLocalizedLabel(CFStringRef label);
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章