天天看點

IOS 之 通訊錄iOS9.0通路通訊錄---ContactsUI和Contacts

在IOS裡通訊錄存放在底層的SQLite3資料庫裡,想要通路它必須需要使用者授權和使用蘋果專門為使用者開放的一些API.

        這裡包含了兩個架構: AddressBook 和 AddressBookUI. 

1.使用這些架構還得引入AddressBook.framework和AddressBookUI.framework庫

2,并且引入所需的頭檔案 #import <AddressBook/AddressBook.h>和#import <AddressBookUI/AddressBookUI.h>

AddressBook架構包含了一些常用的類

ABAddressBook 通路通訊錄接口Core Foundation架構中對應的是ABAddressBookRef

ABPerson 個人資訊 對應 ABPersonRef

ABGroup 一個組包含了多個人的資訊,對應 ABGroupRef

ABRecord 資料庫中的一條記錄對應 ABRecord

AddressBookUI架構包含了4個視圖控制器和4個對應的委托協定他們提供了UI界面

ABPeoplePickerNavigationController  它是從資料庫中聯系人的導航控制器

ABPersonViewController 檢視并編輯單個聯系人資訊

ABNewPersonViewController 建立新聯系人

ABUnKnownPersonViewController 呈現記錄部分資訊,這些資訊可以建立聯系人資訊,或添加到已經存在的聯系人

以下是一些函數的使用說明 (因為ARC的關系,在使用時必須進行一些必要的轉換,轉為foundation的時候需要CFBridgingRelease, 轉為通訊錄函數使用的時候需要CFBridgingRetain, 釋放通訊錄類型的資料時用CFRelease)

特别需要注意的是必須在通訊錄打開的時取出ABRecordRef的多值才有效,是以通常都儲存着id用時再打開通訊錄取多值!

//傳回一個通訊錄的接口

ABAddressBookRef ABAddressBookCreateWithOptions (    CFDictionaryRef options,    CFErrorRef* error );  

//向使用者申請通路通訊錄,第二個參數是block為真允許通路。

void ABAddressBookRequestAccessWithCompletion (    ABAddressBookRef addressBook,    ABAddressBookRequestAccessCompletionHandler completion ); 

//擷取授權狀态

ABAuthorizationStatus ABAddressBookGetAuthorizationStatus (void);  

//從通訊錄傳回所有聯系人

CFArrayRef ABAddressBookCopyArrayOfAllPeople (    ABAddressBookRef addressBook );  

//根據聯系人名字查詢

CFArrayRef ABAddressBookCopyPeopleWithName (    ABAddressBookRef addressBook,    CFStringRef name ); 

//根據記錄的id查詢

ABRecordRef ABAddressBookGetPersonWithRecordID (    ABAddressBookRef addressBook,    ABRecordID recordID );  

//根據一條記錄,來擷取聯系人的相關資訊,CFTypeRef是個泛型,例如id類型,如果傳回一對多的值會是ABMultiValueRef類型,例如電話,emal

CFTypeRef ABRecordCopyValue (    ABRecordRef record,    ABPropertyID property );

//針對一對多的時候來取值 

CFArrayRef ABMultiValueCopyArrayOfAllValues (    ABMultiValueRef multiValue );  

//針對一對多的時候來取标簽名

CFStringRef ABMultiValueCopyLabelAtIndex (    ABMultiValueRef multiValue,    CFIndex index );  

//每條記錄都有一個id是唯一的,ABRecordID可以轉換為Number類型

ABRecordID ABRecordGetRecordID (    ABRecordRef record );  

//根據記錄取聯系人照片,對應 NSData

CFDataRef ABPersonCopyImageData (    ABRecordRef person );

//判斷是否有聯系人照片  

bool ABPersonHasImageData (    ABRecordRef person ); 

建立删除聯系人時用以下六個函數

//傳回一條新增的空記錄

ABRecordRef ABPersonCreate (    void );  

//設定相應的屬性值

bool ABRecordSetValue (    ABRecordRef record,    ABPropertyID property,    CFTypeRef value,    CFErrorRef *error ); 

//建立一對多的值類型

ABMutableMultiValueRef ABMultiValueCreateMutable (    ABPropertyType type ); 

//設定一對多的屬性和值,outIdentifier是指定id可為null

bool ABMultiValueAddValueAndLabel (    ABMutableMultiValueRef multiValue,    CFTypeRef value,    CFStringRef label,    ABMultiValueIdentifier *outIdentifier ); 

//增加新聯系人到通訊錄裡邊

bool ABAddressBookAddRecord (    ABAddressBookRef addressBook,    ABRecordRef record,    CFErrorRef *error ); 

//儲存

bool ABAddressBookSave (    ABAddressBookRef addressBook,    CFErrorRef *error ); 

//根據記錄删除聯系人

bool ABAddressBookRemoveRecord (    ABAddressBookRef addressBook,    ABRecordRef record,    CFErrorRef *error ); 

iOS9.0通路通訊錄---ContactsUI和Contacts

一. 簡介

  1. 在iOS9.0之前, 由于幾乎隻能通過使用了CoreFoundation的AddressBook架構來擷取聯系人資訊, 為了避免使用這個蛋疼繁瑣的架構, 絕大多數的程式員都使用了封裝好的三方架構, 由此引起了蘋果的重視, 終于在iOS9.0之後, 推出了最新的架構ContactsUI和Contacts專門來擷取聯系人資訊
  2. 特點:
    • ContactsUI和Contacts的使用方法與AddressBookUI和AddressBook基本相同
    • 可以把這個新架構了解為面向對象版本的封裝
    • 但是隻能在iOS9.0以後的版本使用

二. 簡單使用ContactsUI

IOS 之 通訊錄iOS9.0通路通訊錄---ContactsUI和Contacts
IOS 之 通訊錄iOS9.0通路通訊錄---ContactsUI和Contacts
  1. ContactsUI是有圖形界面的聯系人擷取方法, 他可以建立

    CNContactPickerViewController

    來建立UI界面
  2. 當使用這個架構的時候, 系統會自動發送授權申請, 不需要手動授權
  3. 注意點:
    • 這個架構主要是使用其代理方法來擷取資料的
    • 如果實作了點選聯系人調用的代理方法的話, 聯系人詳情界面就不會顯示了
    • 遵守的協定為: <CNContactPickerDelegate>
      - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
            
            // 1. 建立選擇聯系人控制器
            CNContactPickerViewController *pickerVC = [[CNContactPickerViewController alloc] init];
            
            // 2. 設定代理
            pickerVC.delegate = self;
            
            // 3. 彈出控制器
            [self presentViewController:pickerVC animated:YES completion:nil];
        }
        
        #pragma mark - 代理方法
        // 控制器點選取消的時候調用
        - (void)contactPickerDidCancel:(CNContactPickerViewController *)picker {
            NSLog(@"點選了取消");
        }
        
        // 點選了聯系人的時候調用, 如果實作了這個方法, 就無法進入聯系人詳情界面
        - (void)contactPicker:(CNContactPickerViewController *)picker didSelectContact:(CNContact *)contact {
            
            // contact屬性就是聯系人的資訊
            NSLog(@"%@---%@", contact.namePrefix, contact.familyName);
            
            // 擷取聯系人的電話号碼
            NSArray<CNLabeledValue<CNPhoneNumber*>*> *phoneNumbers = contact.phoneNumbers;
            
            // 注意, 由于這個數組規定了泛型, 是以要使用周遊器來取出每一個特定類型的對象, 才能取到裡面的屬性
            [phoneNumbers enumerateObjectsUsingBlock:^(CNLabeledValue<CNPhoneNumber*> * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
                
                NSLog(@"%@--%@", obj.label, obj.value.stringValue);
            }];
        }
        
        // 點選了聯系人的詳細屬性的時候調用, 注意, 上邊和這個方法隻能實作一個
        - (void)contactPicker:(CNContactPickerViewController *)picker didSelectContactProperty:(CNContactProperty *)contactProperty {
            NSLog(@"%@---%@", contactProperty.key, contactProperty.value);
        }
                 

三. 簡單使用Contacts

  1. Contacts是沒有UI界面的ContactsUI, 他與AddressBook的使用方法大緻相同
  2. 注意點:
    • 使用這個架構, 要手動申請授權
    • 該架構完全改為了面向對象的OC版本, 而不再使用C函數了
    • 核心步驟為:

      配置請求Key -> 建立請求對象 -> 使用聯系人倉庫發送請求

  3. 大緻步驟
    1. 發送授權申請
      // 1. 擷取權限
       - (void)getAuthor {
           
           // 1. 判斷目前的授權狀态
           if ([CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts] == CNAuthorizationStatusNotDetermined) {
               
               CNContactStore *store = [[CNContactStore alloc] init];
               [store requestAccessForEntityType:CNEntityTypeContacts completionHandler:^(BOOL granted, NSError * _Nullable error) {
                   if (granted) {
                       NSLog(@"授權成功");
                   } else {
                       NSLog(@"授權失敗");
                   }
               }];
           }
       }
                 
    2. 擷取所有聯系人的資訊
      // 2. 擷取所有聯系人的資訊
       - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
           
           // 1. 判斷授權狀态
           if ([CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts] != CNAuthorizationStatusAuthorized) {
               NSLog(@"請授權");
               return;
           }
           
           // 2. 擷取聯系人倉庫
           CNContactStore *store = [[CNContactStore alloc] init];
           
           // 3. 建立聯系人資訊的請求對象
           NSArray *keys = @[CNContactGivenNameKey, CNContactFamilyNameKey, CNContactPhoneNumbersKey];
           
           // 4. 根據請求Key, 建立請求對象
           CNContactFetchRequest *request = [[CNContactFetchRequest alloc] initWithKeysToFetch:keys];
           
           // 5. 發送請求
           [store enumerateContactsWithFetchRequest:request error:nil usingBlock:^(CNContact * _Nonnull contact, BOOL * _Nonnull stop) {
               
               // 6.1 擷取姓名
               NSString *givenName = contact.givenName;
               NSString *familyName = contact.familyName;
               NSLog(@"%@--%@", givenName, familyName);
               
               // 6.2 擷取電話
               NSArray *phoneArray = contact.phoneNumbers;
               for (CNLabeledValue *labelValue in phoneArray) {
                   
                   CNPhoneNumber *number = labelValue.value;
                   NSLog(@"%@--%@", number.stringValue, labelValue.label);
               }
           }];
       }