iOSアドレス帳のバックアップ、リカバリ


アルバムのバックアップと同じように、会社の製品のバックアップ機能には通信録のバックアップ機能があり、自然に通信録の回復もあります.iOSの通信録に関する操作は、iOSの通信録に対する操作に欠かせないフレームワークである.
#import <AddressBook/AddressBook.h>
#import <AddressBookUI/AddressBookUI.h>
iOSは私たちに通信録に関する情報を提供し、簡単な通信録のコントローラ、UIも提供してくれましたが、カスタマイズ可能な部分は少なく、一般的に彼のUIを使わずに、私たちは彼が提供したUIの部分をあまり話しません.(だいたい色、コンポーネントとか、ナビゲーションバーの色などを変えることもできます).
通信録の使用といえば、まず権限の問題ですが、iOS 7以前はユーザー権限を申請する必要はありませんでしたが、iOS 7以降、アップルはユーザーのプライバシーを重視し始めました.例えば、アルバム、通信録、地理的位置などの情報はユーザーの許可を得る必要があります.
まずユーザー権限を申請します.
- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.view.backgroundColor=[UIColor colorWithRed:248.0/255.0 green:248.0/255.0 blue:248.0/255.0 alpha:1.0];
    self.title=@" ";
    [self initView];
    [self addRightBarItem];
    CFErrorRef error=NULL;
    // 
    ABAddressBookRef addressBook=ABAddressBookCreateWithOptions(NULL, &error);
    ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) {
    });
    if (error==NULL) {
        CFRelease(addressBook);
    }
    
    
}
ユーザー権限を取得してから、AddressBookに関する操作を行うことができます.
ただし、権限を取得しても、ユーザーは設定中に私たちの権限をオフにすることができます.AddressBookの操作のたびに、権限が正常かどうかを確認します.
// 
+(BOOL)checkAuthorizationStatus{
    if (ABAddressBookGetAuthorizationStatus()!=kABAuthorizationStatusAuthorized) {
        return NO;
    }else{
        return YES;
    }
}

次に、すべての通信録データを取得します.
-(NSMutableArray *)getLocationAllPeople{
    [self.allPeople removeAllObjects];
    if (![JYAddressBookSyncManager checkAuthorizationStatus]) {
        return self.allPeople;
    }else{
        
        if (ABAddressBookGetAuthorizationStatus()!=kABAuthorizationStatusAuthorized) {
        }else{
        }
        CFErrorRef error = NULL;
        ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, &error);
        CFArrayRef results = ABAddressBookCopyArrayOfAllPeople(addressBook);
        for (int i = 0; i<CFArrayGetCount(results); i++) {
            ABRecordRef person = CFArrayGetValueAtIndex(results, i);
            Person * people = [[Person alloc]init];
            people.id = ABRecordGetRecordID(person);
            people.first_name = CFBridgingRelease(ABRecordCopyValue(person, kABPersonFirstNameProperty));
            
            people.last_name = CFBridgingRelease(ABRecordCopyValue(person, kABPersonLastNameProperty));
            
            people.nick = CFBridgingRelease(ABRecordCopyValue(person, kABPersonNicknameProperty));
            
            people.desc = CFBridgingRelease(ABRecordCopyValue(person, kABPersonNoteProperty));
            
            people.org = CFBridgingRelease(ABRecordCopyValue(person, kABPersonOrganizationProperty));
            
            people.birth =CFBridgingRelease(ABRecordCopyValue(person, kABPersonBirthdayProperty));
            
            // 。
            ABMultiValueRef emailsProperty=ABRecordCopyValue(person, kABPersonEmailProperty);
            
            NSArray *emailsArray=CFBridgingRelease(ABMultiValueCopyArrayOfAllValues(emailsProperty));
            if(emailsArray.count>0){
                NSString *email=[emailsArray objectAtIndex:0];
                people.email = email;
            }
            CFRelease(emailsProperty);
            // 
            ABMultiValueRef phoneNumbersProperty = ABRecordCopyValue(person, kABPersonPhoneProperty);
            NSArray * phoneNumberArray = CFBridgingRelease(ABMultiValueCopyArrayOfAllValues(phoneNumbersProperty));
            for (int j =  0; j<phoneNumberArray.count; j++) {
                NSString *phoneNumber=[phoneNumberArray objectAtIndex:j];
                //            NSString *phoneNumberLabel=CFBridgingRelease(ABMultiValueCopyLabelAtIndex(phoneNumbersProperty, j));
                if(j == 0){
                    people.tel = phoneNumber;
                }else if (j == 1){
                    people.mobile = phoneNumber;
                }else if (j == 2){
                    people.home = phoneNumber;
                }else if (j == 3){
                    people.office = phoneNumber;
                }
            }
            CFRelease(phoneNumbersProperty);
            // 
            //        ABMultiValueRef address = ABRecordCopyValue(person, kABPersonAddressProperty);
            //        int count = (int)ABMultiValueGetCount(address);
            //        if(count>0){
            //            people.addr = CFBridgingRelease(ABMultiValueCopyValueAtIndex(address, 0));
            //        }
            [self.allPeople addObject:people];
            CFRelease(person);
        }
        NSLog(@" :%@",self.allPeople);
        CFRelease(addressBook);
        
        return self.allPeople;
    }
    
}

当社の通信録モジュールは初期バージョンで、サービス側は汎用モード(iOS Android汎用)を設計しているため、番号の読み取りとメールボックスの面では、差が強く、番号サービス側は4つの番号フィールドを制限し、メールボックスは1つしかありません.特筆すべきは、Addressbookが提供してくれたのは2つの配列で、1つは番号配列で、1つはラベル配列です.しかし、すべてc配列で、私たちは変換します.私の上のコードには関連するラベルがありません.サービス側の規定が4つ死んだからです.
次に、通信録の復元:(2つのモード)
1、ローカル所有を削除し、上書きする
//  ( )
-(void)resumeWithDeleteLocation:(AddressPeople*)people andComplete:(deleteSuccessBlock)block{
    if (![JYAddressBookSyncManager checkAuthorizationStatus]) {
        
    }else{
        [self getNetworkAllPeopleWithPeople:people andComplete:^(NSMutableArray *netData) {
            // 
            CFErrorRef error = NULL;
            ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, &error);
            CFArrayRef results = ABAddressBookCopyArrayOfAllPeople(addressBook);
            for (id peo in (__bridge NSArray *)results) {
                ABRecordRef oldPeople = (__bridge ABRecordRef)(peo);
                if (!oldPeople) {
                    break;
                }
                CFErrorRef error = NULL;
                ABAddressBookRemoveRecord(addressBook, oldPeople, &error);
                CFRelease(oldPeople);
            }
            ABAddressBookSave(addressBook, &error);
            CFRelease(addressBook);
            for (Person * person in netData) {
                if(person.tel.length>0||person.mobile.length>0||person.office.length>0||person.home.length>0){
                    [self addLocalPersonWithNetPerson:person];
                }
            }
            [SXLoadingView showAlertHUD:@" " duration:0.5];
            block(people);
        }];
    }
    
}

逐条追加
//
-(void)addLocalPersonWithNetPerson:(Person *)per{
    ABAddressBookRef addressBook = ABAddressBookCreate();
    ABRecordRef person = ABPersonCreate();
    //  
    NSMutableArray * phones = [NSMutableArray array];
    NSMutableArray * labels = [NSMutableArray array];
    if(per.tel.length>0){
        [phones addObject:per.tel];
        [labels addObject:@" "];
    }
    if(per.home.length>0){
        [phones addObject:per.home];
        [labels addObject:@" "];
    }
    if(per.mobile.length>0){
        [phones addObject:per.mobile];
        [labels addObject:@" "];
    }
    if(per.office.length>0){
        [phones addObject:per.office];
        [labels addObject:@" "];
    }
    
    if(per.first_name.length>0||per.last_name.length>0){
        ABRecordSetValue(person, kABPersonFirstNameProperty, (__bridge CFStringRef)per.first_name, NULL);
        ABRecordSetValue(person, kABPersonLastNameProperty, (__bridge CFStringRef) per.last_name, NULL);
    }
    else{
        ABRecordSetValue(person, kABPersonFirstNameProperty, (__bridge CFTypeRef)(per.name), NULL);
    }
    //  birthday 
    //ABRecordSetValue(person, kABPersonBirthdayProperty, (__bridge CFDateRef)per.birth, NULL);
    ABMultiValueRef mv = ABMultiValueCreateMutable(kABMultiStringPropertyType);
    //  
    for (int i = 0; i < [phones count]; i ++) {
        ABMultiValueIdentifier mi = ABMultiValueAddValueAndLabel(mv, (__bridge CFStringRef)[phones objectAtIndex:i], (__bridge CFStringRef)[labels objectAtIndex:i], &mi);
    }
    
    ABRecordSetValue(person, kABPersonPhoneProperty, mv, NULL);
    if (mv) {
        CFRelease(mv);
    }
    ABAddressBookAddRecord(addressBook, person, NULL);
    ABAddressBookSave(addressBook, NULL);
    if (addressBook) {
        CFRelease(addressBook);
    }
}

2つ目は、連絡先を統合します.jsonのコード構造が異なるため,各mergeの対比アルゴリズムが異なる.私たちの比較は堅苦しい.後で改善します.
#pragma mark -  
-(void)mergeAddressBookWithLocalAndNet:(AddressPeople *)people andComplete:(mergeSeccessBlock)block{
    [self getNetworkAllPeopleWithPeople:people andComplete:^(NSMutableArray *netData) {
        NSMutableArray *localPersons = [self getLocationAllPeople];
        for (Person * person in netData) {
            BOOL isHave = NO;
            for (Person * localPerson in localPersons) {
                isHave = [self isSamePeopleByPeople:person OtherPeople:localPerson];
                if (isHave) {
                    break;
                }
            }
            if(isHave){
                [self updateLocalPersonWithNetPerson:person];
            }
            else{
                [self addLocalPersonWithNetPerson:person];
            }
        }
        block();
    }];
}


-(BOOL)isSamePeopleByPeople:(Person*)person OtherPeople:(Person*)otherPerson{
    // name 
    NSMutableArray * phoneNumArr = [NSMutableArray array];
    if(otherPerson.tel){
        [phoneNumArr addObject:otherPerson.tel];
    }
    if (otherPerson.home) {
        [phoneNumArr addObject:otherPerson.home];
    }
    if (otherPerson.office) {
        [phoneNumArr addObject:otherPerson.office];
    }
    if (otherPerson.mobile) {
        [phoneNumArr addObject:person.mobile];
    }
//    NSLog(@"personName:%@  first:%@ last:%@ - otherPersonName:%@ %@",person.name,person.first_name,person.last_name, otherPerson.first_name,otherPerson.last_name);
    if(!IsNilString(person.name)){
        if ([person.name isEqualToString:otherPerson.first_name]||[person.name isEqualToString:[NSString stringWithFormat:@"%@ %@",otherPerson.first_name,otherPerson.last_name]]) {
            if ([phoneNumArr indexOfObject:person.tel] != NSNotFound) {
                return YES;
            }
        }
    }
    else if ([person.first_name isEqualToString:otherPerson.first_name]&&([person.last_name isEqualToString:otherPerson.last_name]||IsNilString(person.last_name)==IsNilString(otherPerson.last_name))) {
        if ([phoneNumArr indexOfObject:person.tel] != NSNotFound) {
            return YES;
        }
    }
    return NO;
}

同じ連絡先がある場合.ではupadteがなければAddします.
-(void)updateLocalPersonWithNetPerson:(Person *)person{
    Person *peopleOfLocation;
    if (self.allPeople.count!=0) {
        for (Person * p in self.allPeople) {
            if (p.id==person.id) {
                peopleOfLocation=p;
                break;
            }
        }
        CFErrorRef error=NULL;
        ABAddressBookRef addressBook=ABAddressBookCreateWithOptions(NULL, &error);
        ABRecordRef person1=ABAddressBookGetPersonWithRecordID(addressBook, peopleOfLocation.id);
        // 
        if (IsNilString(peopleOfLocation.nick)) {
            ABRecordSetValue(person1, kABPersonNicknameProperty, (__bridge CFTypeRef)person.nick, &error);
        }
        if (IsNilString(peopleOfLocation.desc)) {
            ABRecordSetValue(person1, kABPersonNoteProperty, (__bridge CFTypeRef)person.desc, &error);
        }
        if (IsNilString(peopleOfLocation.org)) {
            ABRecordSetValue(person1, kABPersonOrganizationProperty, (__bridge CFTypeRef)person.org, &error);
        }
        if (!peopleOfLocation.birth) {
            ABRecordSetValue(person1, kABPersonBirthdayProperty, (__bridge CFTypeRef)person.birth, &error);
        }
        // 
        // 
        ABMutableMultiValueRef multi=ABMultiValueCreateMutable(kABMultiStringPropertyType);
         NSArray * phoneNumberArray = CFBridgingRelease(ABMultiValueCopyArrayOfAllValues(multi));
        if(person.home){
            if([phoneNumberArray indexOfObject:person.home] == NSNotFound){
                ABMultiValueIdentifier mi = ABMultiValueAddValueAndLabel(multi, (__bridge CFStringRef)person.home, (__bridge CFStringRef)@" ", &mi);
            }
        }
        if(person.office){
            if([phoneNumberArray indexOfObject:person.office] == NSNotFound){
                ABMultiValueIdentifier mi = ABMultiValueAddValueAndLabel(multi, (__bridge CFStringRef)person.office, (__bridge CFStringRef)@" ", &mi);
            }
        }
        if (person.mobile) {
            if([phoneNumberArray indexOfObject:person.mobile] == NSNotFound){
                ABMultiValueIdentifier mi = ABMultiValueAddValueAndLabel(multi, (__bridge CFStringRef)person.mobile, (__bridge CFStringRef)@" ", &mi);
            }
        }
            
        ABRecordSetValue(person1, kABPersonPhoneProperty, multi, &error);
        CFRelease(multi);
        
        
        // 
        ABAddressBookAddRecord(addressBook, person1, &error);
        // 
        ABAddressBookSave(addressBook, &error);
        //        CFRelease(person);
        CFRelease(addressBook);
    }

}

多分これだけです.AddressBookSyncManagerは1つで十分です.