在以往的ios開發中,開發者需要獲取用戶的通訊錄信息的時候,往往要使用AddressBook.frame框架,該框架是純C語言的API,在開發過程中,還需要開發者手動的管理內存,這對於新進開發者很難理解和掌握。到了IOS9,蘋果推出了具有OC語言的API,即Contacts框架,該框架理解簡單、易於使用。聯系人信息可以短時間獲取、創建和修改,而且還不需要去關系對象的釋放。
下面我們介紹一下Contacts框架:
在ios8以后,蘋果更加注重用戶的隱私,因此需要訪問用戶通訊錄的時候,必須給用戶發送授權請求,得到用戶的確認后,才能進行下一步的操作。如果用戶不同意,用戶禁止APP獲取其通訊錄信息,那么這個決定必須被APP采納,且絕對不能與用戶的通訊錄信息交互。不僅如此,用戶隨時可以在設置中更改對APP的授權,因此在任何操作的時候,都需要檢查用戶的授權狀態。
1 //1 判斷是否授權成功 2 if ([CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts] == CNAuthorizationStatusAuthorized) return;//授權成功直接返回 3 //2 創建通訊錄 4 CNContactStore *store = [[CNContactStore alloc] init]; 5 //3授權 6 [store requestAccessForEntityType:CNEntityTypeContacts completionHandler:^(BOOL granted, NSError * _Nullable error) { 7 if (granted) { 8 NSLog(@"授權成功"); 9 }else{ 10 NSLog(@"授權失敗"); 11 } 12 }];
authorizationStatusForEntityType:methods這個方法是CNContactStore的類方法,需要一個 CNEntityType 參數,返回值是授權得到的狀態CNAuthorizationStatus,一共有四種,分別為:
- NotDetermined:表示用戶還沒有允許或禁止訪問通訊錄數據庫。首次安裝的應用軟件處於這種狀態。
- Restricted:不僅應用軟件無法訪問通訊錄數據,就連用戶也無法通過設置修改授權狀態。該狀態是由於其他限制,也就是家長控制(parental control)所導致。
- Denied:表示用戶不允許訪問通訊錄數據。只有用戶才能夠修改該狀態。
- Authorized:這是每個應用軟件期望得到的狀態。在該狀態下,應用軟件可以隨意訪問通訊錄數據庫,使用通訊錄數據執行操作。
我們其實只需要判斷授權狀態是否為 CNAuthorizationStatusAuthorized 即可,如果是表示授權狀態成功,否則失敗,不允許訪問通訊錄。
CNContactStore (相當於ABAddressBook)類以編程方式展示了聯系人數據庫,並且提供了許多實現不同任務的方法,例如獲取,保存或者更新記錄,權限檢查和權限請求,很多很多。
CNContact類(相當於ABRecordRef)展示一個單獨的聯系人記錄,但是記住這個類的特性是不可變的。如果你想創建一個新的聯系人記錄或者更新一個已存在的聯系人記錄,你必須使用CNMutableContact類。
需要注意的是在於Contacts框架打交道的時候,特別是獲取聯系人信息時,你應該始終在后台線程中運行這些任務。因為如果一個聯系人信息獲取任務花去了太多時間而且在主線程運行,那么你的應用有可能無響應,然后最終導致非常糟糕的交互體驗。
於此同時在導入聯系人信息到APP時,很少用到所有的聯系人的屬性信息。在所有的Contacts 框架要搜索的數據源中獲取所有聯系人數據的操作,被證明是一個非常耗資源的進程,所以應該避免檢索所以聯系人的屬性信息,而是只檢索需要的一部分屬性信息,這個是在Contacts框架提供了的。例如,你可以只是請求名或姓,電話等,這樣可以通過排除不需要的那些數據來節約很多資源。
查詢聯系人代碼示例:
1 /** 查看聯系人 */ 2 - (void)readContact { 3 if ([CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts] != CNAuthorizationStatusAuthorized) return;//授權失敗直接返回 4 5 //創建通訊錄對象 6 CNContactStore *store = [[CNContactStore alloc] init]; 7 8 // 創建獲取通信錄的請求對象 9 //拿到所有打算獲取的屬性對應的key(這里僅僅指定需要獲取的數據,節約資源) 10 //我們這里僅僅作為示例,所以獲取了所有的信息數據 11 NSArray *typeArray = @[CNContactGivenNameKey,CNContactFamilyNameKey,CNContactPhoneNumbersKey,CNContactEmailAddressesKey,CNContactBirthdayKey,CNContactDepartmentNameKey]; 12 13 //創建CNContactFetchRequest對象 14 CNContactFetchRequest *request = [[CNContactFetchRequest alloc] initWithKeysToFetch:typeArray]; 15 16 //遍歷所有的聯系人 17 [store enumerateContactsWithFetchRequest:request error:nil usingBlock:^(CNContact * _Nonnull contact, BOOL * _Nonnull stop) { 18 19 //名字 20 NSString *firstName = contact.givenName; 21 //姓氏 22 NSString *lastName = contact.familyName; 23 24 NSLog(@"%@ -- %@", firstName, lastName); 25 26 //獲取電話信息 27 NSArray *phones = contact.phoneNumbers; 28 for (int i = 0; i<phones.count; i++) { 29 30 CNLabeledValue *phone = phones[i]; 31 32 //獲取電話號碼的KEY 33 NSString *label = phone.label; 34 35 //獲取電話號碼 36 CNPhoneNumber *phoneNum = phone.value; 37 NSString *num = phoneNum.stringValue; 38 NSLog(@"name= %@ -- num = %@", label, num); 39 } 40 }]; 41 42 }
插入聯系人示例:
1 /** 2 * 添加聯系人 3 */ 4 - (IBAction)addContact { 5 6 //1、聯系人對象:CNContact 7 8 //這個對象是用來配置聯系人信息的,有可變的CNMutaleContact和CNContact,區別用來讀取和創建聯系人。CNContact對象中有許多屬性,對應聯系人的一些信息。 9 10 //首先,創建CNMutableContact對象: 11 CNMutableContact *contact = [[CNMutableContact alloc]init]; 12 13 //設置聯系人數據 14 [self setupContact:contact]; 15 16 17 //2、創建添加聯系人請求:CNSaveRequest 18 //CNSaveRequest是用於存儲聯系人的請求類,通過這個類,我們可以創建批量添加、修改或者刪除聯系人的請求,例如添加上面我們創建的聯系人對象: 19 20 //初始化方法 21 CNSaveRequest * saveRequest = [[CNSaveRequest alloc] init]; 22 //添加聯系人 23 [saveRequest addContact:contact toContainerWithIdentifier:nil]; 24 25 //3 進行聯系人的寫入操作:CNContactStore 26 //CNContactStore是一個用於存取聯系人的上下文橋梁,現在,把我們創建的添加聯系人的請求寫入: 27 CNContactStore * store = [[CNContactStore alloc]init]; 28 [store executeSaveRequest:saveRequest error:nil]; 29 } 30 31 /** 設置聯系人信息 */ 32 - (void)setupContact:(CNMutableContact *)contact{ 33 //設置聯系人頭像: 34 contact.imageData = UIImagePNGRepresentation([UIImage imageNamed:@"tour"]); 35 36 //設置聯系人姓名: 37 //設置名字 38 contact.givenName = @"xiao"; 39 //設置姓氏 40 contact.familyName = @"zhang"; 41 42 //設置聯系人郵箱(這里需要注意,emailAddresses屬性是一個數組,數組中是才CNLabeledValue對象) 43 CNLabeledValue *homeEmail = [CNLabeledValue labeledValueWithLabel:CNLabelHome value:@"3242523553@qq.com"]; 44 CNLabeledValue *workEmail =[CNLabeledValue labeledValueWithLabel:CNLabelWork value:@"324266653@qq.com"]; 45 contact.emailAddresses = @[homeEmail,workEmail]; 46 47 //設置聯系人電話(和郵箱類似) 48 CNLabeledValue *mianPhone = [CNLabeledValue labeledValueWithLabel:CNLabelPhoneNumberMain value:[CNPhoneNumber phoneNumberWithStringValue:@"6363524"]]; 49 CNLabeledValue *homePhone = [CNLabeledValue labeledValueWithLabel:CNLabelPhoneNumberHomeFax value:[CNPhoneNumber phoneNumberWithStringValue:@"1536312321"]]; 50 contact.phoneNumbers = @[mianPhone, homePhone]; 51 52 //設置聯系人地址 53 CNMutablePostalAddress * homeAdress = [[CNMutablePostalAddress alloc]init]; 54 homeAdress.street = @"大雁塔"; 55 homeAdress.city = @"西安"; 56 homeAdress.state = @"中國"; 57 homeAdress.postalCode = @"xxxxx"; 58 contact.postalAddresses = @[[CNLabeledValue labeledValueWithLabel:CNLabelHome value:homeAdress]]; 59 60 //設置聯系人生日 61 NSDateComponents * birthday = [[NSDateComponents alloc] init]; 62 birthday.day=7; 63 birthday.month=9; 64 birthday.year=1998; 65 contact.birthday=birthday; 66 }
ContactsUI.frame框架
1 //打開通訊錄 2 - (IBAction)openContact { 3 //初始化ContactPickerViewController 4 CNContactPickerViewController *pickVc = [[CNContactPickerViewController alloc] init]; 5 //成為自己的代理 6 pickVc.delegate = self; 7 //跳轉控制器 8 [self presentViewController:pickVc animated:YES completion:nil]; 9 } 10 11 #pragma mark - CNContactPickerDelegate 12 // 點擊cancle按鈕時候就會調用 13 - (void)contactPickerDidCancel:(CNContactPickerViewController *)picker{ 14 NSLog(@"%s", __func__); 15 [picker dismissViewControllerAnimated:YES completion:nil]; 16 } 17 18 // 選中某一個聯系人就會調用 19 //注意:只要實現了這個方法, 就不會進行下一步操作(進入詳情), iOS9的做法是默認返回NO 20 - (void)contactPicker:(CNContactPickerViewController *)picker didSelectContact:(CNContact *)contact{ 21 NSLog(@"%s", __func__); 22 //姓氏 23 NSString *firstName = contact.familyName; 24 //名字 25 NSString *lastName = contact.givenName; 26 NSLog(@"%@---%@", firstName, lastName); 27 //電話信息 28 NSArray *phones = contact.phoneNumbers; 29 for (CNLabeledValue *phone in phones) { 30 //電話名稱 31 NSString *name = phone.label; 32 //電話號碼詳情 33 CNPhoneNumber *phoneNum = phone.value; 34 NSLog(@"name = %@, phoneNum = %@", name, phoneNum.stringValue); 35 } 36 37 } 38 39 // 選中某一個聯系人的某一個屬性時就會調用 40 - (void)contactPicker:(CNContactPickerViewController *)picker didSelectContactProperty:(CNContactProperty *)contactProperty{ 41 NSLog(@"%s", __func__); 42 }