en

hi, it seems you are using microsoft internet explorer. it doesn't match web standard and causes problems browsing this site. please please please use mozilla firefox or google chrome instead. thank you!

zh

哦哦!您正在使用Internet Explorer 瀏覽器,它與我們的網頁標準並不相容,可能會導致畫面顯示不正常。
請改用 Mozilla Firefox 或者 Google Chrome 才能正常瀏覽本網站,謝謝!

6.15.2012

取得 Address Book 聯絡資訊內容的方法

  

Address Book 聯絡資訊是內建在 iOS 中的一個重要的應用程式,它記錄了所有人員聯絡資訊的相關資料,包含姓名、電話、住址、網站、公司的職稱與部門、生日或是紀念日等等資訊,下面就是要示範如何取得這些已經存在於裝置中的聯絡資訊。

若要取得聯絡資訊中的資料必須透過 iOS SDK 所提供的 AddressBook Framework 來完成,所以首先我們必須先以手動的方式替專案新增 AddressBook.framework,並且引用對應的標頭檔。

手動替專案新增 AddressBook.framework
#import < AddressBook/Addressbook.h>
對於新增 Framework 有問題的讀者們,請參考 Xcode 4 新增 Framework 的方法一文。


取得聯絡資訊的所有內容
請參考以下程式碼從聯絡資訊中取得聯絡人資料,以每一筆為單位,在成功取得每一筆資料後才去分析其中的聯絡資訊。
//建立與判斷是否成功建立聯絡資訊的資料
ABAddressBookRef myAddressBook = ABAddressBookCreate();

if (myAddressBook) {

    //取得聯絡資訊裡的每筆資料並計算總數
    CFArrayRef arrayOfEntries = ABAddressBookCopyArrayOfAllPeople(myAddressBook);
    CFIndex countOfEntries = CFArrayGetCount(arrayOfEntries);

    //取得聯絡資訊中的每筆資料
    for (int i=0; i!=countOfEntries; i++) {
        ABRecordRef currentRecord = CFArrayGetValueAtIndex(arrayOfEntries, i);

        //
        //分析currentRecord以取得詳細的聯絡資訊
        //
    }

    NSLog(@"共有 %ld 筆資料", countOfEntries);
    CFRelease(arrayOfEntries);
}

CFRelease(myAddressBook);

在成功取得每一筆資料後,下面我們將利用每筆資料中的 ABPropertyID 來取得所需要的資料的內容,完整的 ABPropertyID 使用說明,請參考官方 iOS Developer Library 的 ABPerson Reference


取得單一類型的資訊
單一類型的資訊,這裡指的是像姓名或是匿稱這類的單一類型的資訊,這類的資訊在同一筆資料中必須是唯一的,電話號碼就不適用在此範圍內(iOS 允許在同一筆資料中輸入不同類型的電話號碼)。
//姓名與綽號
NSString *lastName = (__bridge_transfer NSString *)ABRecordCopyValue(currentRecord, kABPersonLastNameProperty);
NSString *firstName = (__bridge_transfer NSString *)ABRecordCopyValue(currentRecord, kABPersonFirstNameProperty);
NSString *nickName = (__bridge_transfer NSString *)ABRecordCopyValue(currentRecord, kABPersonNicknameProperty);

NSLog(@"姓名:%@ %@", lastName, firstName);
NSLog(@"綽號:%@", nickName);

在上述的程式碼中,我們使用 ABRecordCopyValue 配合 ABPropertyID,來取得每筆資料中我們所感興趣的單一類型資訊。

取得單一類型資訊的結果


取得複合類型的資訊
複合類型的資訊,像是電話、電子郵件這類,在同一筆資料中很能存在好幾種相同的種類,例如電話號碼就可以分成行動電話、iPhone 或主要聯絡電話等。

ABMultiValueRef phone = ABRecordCopyValue(currentRecord, kABPersonPhoneProperty);
ABMultiValueRef mail = ABRecordCopyValue(currentRecord, kABPersonEmailProperty);

//電話
for(CFIndex x=0; x!=ABMultiValueGetCount(phone); x++) {
    NSString *phoneLabel = (__bridge_transfer NSString *)ABMultiValueCopyLabelAtIndex(phone, x);

    if ([phoneLabel isEqualToString:(__bridge_transfer NSString *)kABPersonPhoneMobileLabel]) {
        NSLog(@"行動電話:%@", (__bridge_transfer NSString *)ABMultiValueCopyValueAtIndex(phone, x));
    }

    if ([phoneLabel isEqualToString:(__bridge_transfer NSString *)kABPersonPhoneIPhoneLabel]) {
        NSLog(@"iPhone:%@", (__bridge_transfer NSString *)ABMultiValueCopyValueAtIndex(phone, x));
    }

    if ([phoneLabel isEqualToString:(__bridge_transfer NSString *)kABPersonPhoneMainLabel]) {
        NSLog(@"主要電話:%@", (__bridge_transfer NSString *)ABMultiValueCopyValueAtIndex(phone, x));
    }
}

//電子郵件
for(CFIndex x=0; x!=ABMultiValueGetCount(mail); x++) {
    NSLog(@"E-Mail:%@", (__bridge_transfer NSString *)ABMultiValueCopyValueAtIndex(mail, x));
}

在上述的程式碼中,我們使用 ABMultiValueRef 來取得這些複合類型的資訊,並且使用 Index 配合該資料特有的 Label,來取得每筆複合資料中對應的資訊。

取得複合類型資訊的結果


取得其他複合類型的資訊
其他複合類型的資訊,比起上述的複合類型還要在複雜一些,像是聯絡人的地址這類的資訊,地址可以被分拆成好幾部分,例如街道、地區、城市或是國家等等,而這些部分又會依照住家、公司或是其他分類有所不同。
ABMultiValueRef address = ABRecordCopyValue(currentRecord, kABPersonAddressProperty);

//住址
for(CFIndex x=0; x!=ABMultiValueGetCount(address); x++) {

    //判斷不同類型的住址
    NSString* addressLabel = (__bridge_transfer NSString *)ABMultiValueCopyLabelAtIndex(address, x);
    BOOL home = [addressLabel isEqualToString:(__bridge_transfer NSString *)kABHomeLabel];
    BOOL work = [addressLabel isEqualToString:(__bridge_transfer NSString *)kABWorkLabel];
    BOOL other = [addressLabel isEqualToString:(__bridge_transfer NSString *)kABOtherLabel];

    //取得住址的每一部分資訊
    NSDictionary* personAddress =(__bridge_transfer NSDictionary *)ABMultiValueCopyValueAtIndex(address, x);

    NSLog(@"國家名稱:%@", [personAddress valueForKey:(__bridge_transfer NSString *)kABPersonAddressCountryKey]);
    NSLog(@"區域編號:%@", [personAddress valueForKey:(__bridge_transfer NSString *)kABPersonAddressZIPKey]);
    NSLog(@"城市名稱:%@", [personAddress valueForKey:(__bridge_transfer NSString *)kABPersonAddressCityKey]);
    NSLog(@"鄉鎮市區:%@", [personAddress valueForKey:(__bridge_transfer NSString *)kABPersonAddressStateKey]);
    NSLog(@"街道名稱:%@", [personAddress valueForKey:(__bridge_transfer NSString *)kABPersonAddressStreetKey]);
    NSLog(@"國家代碼:%@", [personAddress valueForKey:(__bridge_transfer NSString *)kABPersonAddressCountryCodeKey]);
}

在上述的程式碼中,我們同樣使用 ABMultiValueRef 來取得這些複合類型的資訊,並且使用 Index 配合該資料特有的 Label,來取得住址的分類,這點和上述的「取得複合類型的資訊」小節一樣,但是在住址中又可以在細分成好幾部分,這時就必須使用 NSDictionary 搭配 Key Value 來取得想要的部份了。(上述程式碼中只有使用 kABHomeLabel、kABWorkLabel 和 kABOtherLabel 來做住家、公司或是其他住址的判斷,但是在傾印時並未限制是何種類型的住址)

取得其他複合類型資訊的結果


ps:程式碼中的 __bridge_transfer 為強制轉型。





10 則留言:

  1. 你好 !
    想問 Address book 的Person view controller的內容有辦法修改嗎?
    因為本人發現所顯示的英文地址並不合乎標準的英文地址格式。
    本人想更改person view controller 中的地址顯示次序,謝謝你。

    回覆刪除
    回覆
    1. 匿名者 你好:

      好像沒有版法修改耶,除非你在做一個出來,自己去調整順序。

      如果是地址格式的問題,有可能是裝置語系的問題!

      刪除
  2. 您好

    我想請問一下

    iPhone中有個電話欄位是“公司”

    但是我卻找不到屬於公司的kABperson的label讓我可以取出資料

    是本來就這樣嗎?

    回覆刪除
    回覆
    1. 范凱傑 您好:

      的確使用上述的方式他沒有定義可以讓你使用比較 work 的電話,

      但是您可以試著在每個迴圈中列印出 phoneLabel 字串,如果公司那一欄是有甜電話資料,那麼你應該會得到一個回傳字串 _$!!$_
      你可以將此字串自行定義於 ABperson.h 中,或者直接使用該字串做判斷:

      if ([phoneLabel isEqualToString:@"_$!!$_"]) {
      NSLog(@"公司電話:%@", (__bridge_transfer NSString *)ABMultiValueCopyValueAtIndex(phone, x));
      }

      希望這樣有幫到您!

      刪除
  3. 匿名2/11/2014

    您好,
    兩個問題想請教,
    (1)可不可以把通訊錄裡面的某一個聯絡人變成"我的最愛“聯絡人。
    (2)第一點如果不行,我想要把通訊錄裡面某個聯絡人的kABPersonInstantMessageProperty加一個Label=SIP,
    當成“我的最愛”的特殊Label,但是一直無法修改現有聯絡人的資料加上一個Label... 可否提供範例或是教學指導。


    我在載入我的最愛清單的時候,
    或掃出有該Label的人,並顯示。

    if(CFDictionaryContainsKey(lDict, kABPersonInstantMessageServiceKey)) {
    CFStringRef serviceKey = CFDictionaryGetValue(lDict, kABPersonInstantMessageServiceKey);

    if(CFStringCompare((CFStringRef)@"SIP", serviceKey, kCFCompareCaseInsensitive) == 0) {
    add = true;
    }
    else {
    add=false;
    }
    }
    謝囉。

    回覆刪除
    回覆
    1. 您好:
      本篇文章只有提及如何重聯訓運中取得聯絡人的相關資料,關於您的問題像是修改或是增加聯絡人欄位等等,可以參考網路上其他人的寫法,例如:
      http://iphonedevsdk.com/forum/iphone-sdk-development/12496-add-contact-to-address-book.html

      希望對你有幫助,另外我不確定能不能使用自定欄位來做設定。

      刪除
  4. 匿名5/08/2016

    版主你好,此教學對我有很大的幫助
    最近也在寫有關通訊錄的App
    想請教你如何取到值後想用xml或ajax將值存到mysql作為之後的運用,不知你的看法如何?謝謝

    回覆刪除
    回覆
    1. 您好:

      這些問題都比較偏向web端的技術了,不過你可以在devive中就直接使用SQL語法對資料庫寫入資料,
      在這之前建議妳可以先把資料從通訊簿中撈出來存放在類似NSDictionary的結構裡,
      之後再對此結構操作寫進DB。

      如果再實作上一定要透過網頁,那就開一個Web Service API,device用http post的方式把數值打到此API上,由WEB端做寫入DB的動作

      刪除
    2. 匿名5/13/2016

      版主你好!謝謝你的協助
      目前我們Web端已建置好了
      這幾天有詳細研究你的建議方式,不過還是遇到一些問題
      請問版主不知能否提供這方面的教學?
      謝謝

      刪除
    3. 這邊好像沒有提供這類的教學,

      如果你是手機端要打post的話可以參考這個
      http://wangshifuola.blogspot.tw/2012/01/iospostservernsurlconnection.html

      如果你是網頁端要測試自己的api是否準備好可以使用 postman 這套軟體(chrome有網頁版插件可以用)

      刪除