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);