Just a Computer Graphics Studio & My Life

想要將顯示在App上的聯絡人資料加入到通訊錄,但是不想要讓使用者自己到通訊錄一個字一個字慢慢打,這時候就可以用這些複雜的程式碼解決囉!

Address Book1

以下程式碼觸發點為「儲存到手機通訊錄」,接下來就會把欄位上的資料集結起來,經過幾個步驟就能將聯絡人資料加入通訊錄。此外,還可以判斷此人是否已存在於通訊錄,以免重複加入同樣的聯絡人資料。

/**
 Theme: Address Book
 IDE: Xcode 6
 Language: Objective C
 Date: 103/10/13
 Author: HappyMan
 Blog: https://cg2010studio.wordpress.com/
 */
-(IBAction)saveContactAction:(UIButton *)button
{
    ABAddressBookRef addressBook = NULL;
    CFErrorRef error = NULL;

    switch (ABAddressBookGetAuthorizationStatus()) {
        case kABAuthorizationStatusAuthorized: {
            addressBook = ABAddressBookCreateWithOptions(NULL, &error);

            [self addAccountInAddressBook:addressBook withFirstName:nameLabel.text jobTitle:titleLabel.text cellPhone:cellphoneLabel.text officePhone:officephoneLabel.text email:emailLabel.text image:photoImageView.image];

            if (addressBook != NULL) CFRelease(addressBook);
            break;
        }
        case kABAuthorizationStatusDenied: {
            NSLog(@"Access denied to address book");
            break;
        }
        case kABAuthorizationStatusNotDetermined: {
            addressBook = ABAddressBookCreateWithOptions(NULL, &error);
            ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) {
                if (granted) {
                    NSLog(@"Access was granted");
                    [self addAccountInAddressBook:addressBook withFirstName:nameLabel.text jobTitle:titleLabel.text cellPhone:cellphoneLabel.text officePhone:officephoneLabel.text email:emailLabel.text image:photoImageView.image];
                }
                else NSLog(@"Access was not granted");
                if (addressBook != NULL) CFRelease(addressBook);
            });
            break;
        }
        case kABAuthorizationStatusRestricted: {
            NSLog(@"access restricted to address book");
            break;
        }
    }

    // 判斷此人是否已在通訊錄
    if ([self hasExistRecord:nameLabel.text] == YES) {
        addButton.enabled = NO;

        UIAlertView *contactExistsAlert = [[UIAlertView alloc] initWithTitle: @"成功" message:[NSString stringWithFormat:@"已加入【%@】到通訊錄!", nameLabel.text] delegate:nil cancelButtonTitle:@"確認" otherButtonTitles: nil];
        [contactExistsAlert show];
    }
    else {
        UIAlertView *contactExistsAlert = [[UIAlertView alloc] initWithTitle: @"失敗" message:[NSString stringWithFormat:@"未加入【%@】到通訊錄!", nameLabel.text] delegate:nil cancelButtonTitle:@"確認" otherButtonTitles: nil];
        [contactExistsAlert show];
    }
}

- (ABRecordRef)addAccountInAddressBook:(ABAddressBookRef)addressBook withFirstName:(NSString *)firstName jobTitle:(NSString *)jobTitle cellPhone:(NSString *)cellPhone officePhone:(NSString *)officePhone email:(NSString *)email image:(UIImage *)image
{
    ABRecordRef result = NULL;
    CFErrorRef error = NULL;

    //1
    result = ABPersonCreate();
    if (result == NULL) {
        NSLog(@"Failed to create a new person.");
        return NULL;
    }

    //2
    BOOL couldSetFirstName = ABRecordSetValue(result, kABPersonFirstNameProperty, (__bridge CFTypeRef)firstName, &error);
    BOOL couldSetJobTitle = ABRecordSetValue(result, kABPersonJobTitleProperty, (__bridge CFTypeRef)jobTitle, &error);

    // 多個電話
    ABMutableMultiValueRef phoneNumbers = ABMultiValueCreateMutable(kABMultiStringPropertyType);
    BOOL couldSetCellPhone = ABMultiValueAddValueAndLabel(phoneNumbers, (__bridge CFStringRef)cellPhone, kABPersonPhoneMobileLabel, NULL);
    BOOL couldSetOfficePhone = ABMultiValueAddValueAndLabel(phoneNumbers, (__bridge CFStringRef)officePhone, kABPersonPhoneMainLabel, NULL);
    ABRecordSetValue(result, kABPersonPhoneProperty, phoneNumbers, &error);

    // 多個信箱
    ABMutableMultiValueRef emails = ABMultiValueCreateMutable(kABMultiStringPropertyType);
    BOOL couldSetEmail = ABMultiValueAddValueAndLabel(emails, (__bridge CFStringRef)email, CFSTR("email"), NULL);
    ABRecordSetValue(result, kABPersonEmailProperty, emails, &error);

    // 大頭照
    NSData *photoData = UIImageJPEGRepresentation(image, 0.7);
    BOOL couldSetPhoto = ABPersonSetImageData(result, (__bridge CFDataRef)photoData, nil);

    if (couldSetFirstName && couldSetJobTitle && couldSetCellPhone && couldSetOfficePhone && couldSetEmail && couldSetPhoto) {
        NSLog(@"Successfully set the information of the person.");
    } else {
        NSLog(@"Failed.");
    }

    //3
    BOOL couldAddPerson = ABAddressBookAddRecord(addressBook, result, &error);

    if (couldAddPerson) {
        NSLog(@"Successfully added the person.");
    } else {
        NSLog(@"Failed to add the person.");
        CFRelease(result);
        result = NULL;
        return result;
    }

    //4
    if (ABAddressBookHasUnsavedChanges(addressBook)) {
        BOOL couldSaveAddressBook = ABAddressBookSave(addressBook, &error);

        if (couldSaveAddressBook) {
            NSLog(@"Succesfully saved the address book.");
        } else {
            NSLog(@"Failed.");
        }
    }
    return result;
}

-(BOOL)hasExistRecord:(NSString *)name
{
    CFErrorRef error = NULL;
    ABRecordRef result = ABPersonCreate();
    ABRecordSetValue(result, kABPersonFirstNameProperty, (__bridge CFTypeRef)name, &error);

    ABAddressBookRef addressBookRef = ABAddressBookCreateWithOptions(NULL, &error);
    NSArray *allContacts = (__bridge NSArray *)ABAddressBookCopyArrayOfAllPeople(addressBookRef);

    for (id record in allContacts){
        ABRecordRef thisContact = (__bridge ABRecordRef)record;
        if (CFStringCompare(ABRecordCopyCompositeName(thisContact),
                            ABRecordCopyCompositeName(result), 0) == kCFCompareEqualTo){
            return YES;
        }
    }
    return NO;
}

這裡比較需要注意的是,有些欄位可以有多個值,像是電話號碼電子信箱,就要再以標籤細分。而電子信箱的標簽可以自定名稱,例如Gmail、HotMail、YahooMail等。

執行結果就是去通訊錄那兒查看~

Address Book2

疑惑:在iPhone 5c測試正常,在iPhone 6測試會掛掉(檢查聯絡人是否存在通訊錄的功能),原以為是裝有SIM卡的問題,不過抽出來之後測試得到一樣的結果。我在想會不會跟SIM卡無法「導入SIM卡通訊錄」有關係?那麼有些機子大概都會有類似的問題吧~公司的iPhone 6不會crash,而我的iPhone 6會crash,真是令人匪夷所思⋯⋯

更新:改用簡潔的程式碼來判斷就沒有問題了,原因可能是遇到通訊錄中某個名稱為空的時候,上頭那個判斷方法沒有處理所導致⋯⋯

-(BOOL)hasExistRecord:(NSString *)name
{
    CFErrorRef error = NULL;
    ABAddressBookRef addressBookRef = ABAddressBookCreateWithOptions(NULL, &error);
    NSArray *allContacts = (__bridge NSArray *)ABAddressBookCopyArrayOfAllPeople(addressBookRef);
    for (id record in allContacts){
        ABRecordRef thisContact = (__bridge ABRecordRef)record;
        NSString *thisName = (__bridge_transfer NSString *)ABRecordCopyValue(thisContact, kABPersonFirstNameProperty);
        if ([thisName isEqualToString:name]){
            return YES;
        }
    }
    return NO;
}

後來客戶想改以手機號碼來判斷是否已加入通訊錄,也不是不能這麼做,只是有人可能沒有手機號碼(雖然這個時代不太可能),好的使用者體驗應是以人名為主(儘管可能有同名同姓),畢竟我是加你這個人,其它聯絡資料如手機號碼、公司號碼、電子信箱從缺沒關係,之後還能加上去。

-(BOOL)hasExistRecordWithCellPhoneNumber:(NSString *)cellPhoneNumber
{
    if ([cellPhoneNumber isEqualToString:@""]) {
        return NO;
    }
    CFErrorRef error = NULL;
    ABAddressBookRef addressBookRef = ABAddressBookCreateWithOptions(NULL, &error);
    NSArray *allContacts = (__bridge NSArray *)ABAddressBookCopyArrayOfAllPeople(addressBookRef);
    for (id person in allContacts) {
        ABMultiValueRef phoneNumbers = ABRecordCopyValue((__bridge ABRecordRef)(person), kABPersonPhoneProperty);
        for (int i = 0; i < ABMultiValueGetCount(phoneNumbers); i++) {
            NSString *thisCellPhoneNumber = (__bridge NSString*)ABMultiValueCopyValueAtIndex(phoneNumbers, i);
//            NSCharacterSet *trim = [NSCharacterSet characterSetWithCharactersInString:@"#();$&-+"];
//            mobile = [[mobile componentsSeparatedByCharactersInSet:trim] componentsJoinedByString: @""];
//            mobile = [mobile stringByReplacingOccurrencesOfString:@"\"" withString:@""];
//            mobile = [mobile stringByReplacingOccurrencesOfString:@" " withString:@""];
            if ([thisCellPhoneNumber isEqualToString:cellPhoneNumber]){
                return YES;
            }
        }
    }
    return NO;
}

參考:Address Book Tutorial in iOSAdd Contacts to the Address Book in iOS7取得 Address Book 聯絡資訊內容的方法How can I get all phone numbers from addressbook IOS 5 KABPersonPhoneProperty

Advertisements

發表留言

在下方填入你的資料或按右方圖示以社群網站登入:

WordPress.com Logo

您的留言將使用 WordPress.com 帳號。 登出 / 變更 )

Twitter picture

您的留言將使用 Twitter 帳號。 登出 / 變更 )

Facebook照片

您的留言將使用 Facebook 帳號。 登出 / 變更 )

Google+ photo

您的留言將使用 Google+ 帳號。 登出 / 變更 )

連結到 %s

標籤雲

%d 位部落客按了讚: