How to get VCF data with contact images using CNContactVCardSerialization dataWithContacts: method?

前端 未结 3 590
忘了有多久
忘了有多久 2020-12-19 06:25

I\'m using CNContacts and CNContactUI framework and picking a contact via this

CNContactPickerViewController *contactPicker = [CNContactPickerViewController          


        
相关标签:
3条回答
  • 2020-12-19 06:42

    As a workaround you can create PHOTO field inside of VCard.

    NSError* error = nil;
    NSData* vCardData = [CNContactVCardSerialization dataWithContacts:@[contact] error:&error];
    NSString* vcString = [[NSString alloc] initWithData:vCardData encoding:NSUTF8StringEncoding];
    NSString* base64Image = contact.imageData.base64Encoding;
    NSString* vcardImageString = [[@"PHOTO;TYPE=JPEG;ENCODING=BASE64:" stringByAppendingString:base64Image] stringByAppendingString:@"\n"];
    vcString = [vcString stringByReplacingOccurrencesOfString:@"END:VCARD" withString:[vcardImageString stringByAppendingString:@"END:VCARD"]];
    vCardData = [vcString dataUsingEncoding:NSUTF8StringEncoding];
    

    For some reasons CNContactVCardSerialization does not use any photo of contact. VCard after serialization is looks like:

    BEGIN:VCARD
    VERSION:3.0
    PRODID:-//Apple Inc.//iPhone OS 9.3.2//EN
    N:Contact;Test;;;
    FN: Test  Contact 
    END:VCARD
    

    After insertion the PHOTO field inside VCard you will get

    BEGIN:VCARD
    VERSION:3.0
    PRODID:-//Apple Inc.//iPhone OS 9.3.2//EN
    N:Contact;Test;;;
    FN: Test  Contact 
    PHOTO;TYPE=JPEG;ENCODING=BASE64:<photo base64 string>
    END:VCARD
    

    After this insertion contact will looks fine in CNContactViewController

    0 讨论(0)
  • 2020-12-19 06:51

    For N number of contacts, you can add image data into VCF by using simple method as below.

    -(NSData*)getVCFDataWithImagesFromContacts:(NSArray*)arrContacts
    {
    //---- Convert contacts array into VCF data.
        NSError *error;
        NSData *vcfData = [CNContactVCardSerialization dataWithContacts:arrContacts error:&error];
    
    
        //--- Convert VCF data into string.
        NSString *strVCF = [[NSString alloc] initWithData:vcfData encoding:NSUTF8StringEncoding];
    
        //--- Split contacts from VCF.
        NSMutableArray *arrSplit = (NSMutableArray*)[strVCF componentsSeparatedByString:@"END:VCARD"];
        [arrSplit removeLastObject];//-- if object is "\r\n" otherwise comment this line.
    
        //--- Validate array count
        if (arrSplit.count == arrContacts.count)
        {
            for (int index=0;index<arrContacts.count;index++)
            {
                //--- Get current contact and VCF contact string.
                CNContact *contact = arrContacts[index];
                NSString *strContact = arrSplit[index];
    
                //--- Get base64 string of image.
                NSString* base64Image = [UIImagePNGRepresentation([ViewController imageWithImage:[UIImage imageWithData:contact.imageData] scaledToSize:CGSizeMake(50,50)]) base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithCarriageReturn];
    
                //--- Append image tag into contact string.
                NSString* vcardImageString = [[@"PHOTO;ENCODING=BASE64;JPEG:" stringByAppendingString:base64Image] stringByAppendingString:@"\r\n"];
            strContact = [strContact stringByAppendingString:[NSString stringWithFormat:@"%@%@",vcardImageString,@"END:VCARD\r\n"]];
    
                //--- Update contact string from array.
                [arrSplit replaceObjectAtIndex:index withObject:strContact];
                NSLog(@"strContact :%@",strContact);
            }
        }
    
        //--- Combine all contacts together in VCF.
        vcfData =  [[arrSplit componentsJoinedByString:@""] dataUsingEncoding:NSUTF8StringEncoding];
        strVCF = [[NSString alloc] initWithData:vcfData encoding:NSUTF8StringEncoding];//--- VCF Data
    
        NSLog(@"Contact VCF error :%@",error.localizedDescription);
    
        return vcfData;
    }
    
    
    +(UIImage *)imageWithImage:(UIImage *)image scaledToSize:(CGSize)newSize
    {
       UIGraphicsBeginImageContextWithOptions(newSize, NO, 0.0);
       [image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
       UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
       UIGraphicsEndImageContext();
       return newImage;
    }
    
    0 讨论(0)
  • 2020-12-19 07:00

    I'd like to improve upon and modernise for Swift 3 the excellent answer by kudinovdenis.

    Just put the following extension into your project

    import Foundation
    import Contacts
    
    extension CNContactVCardSerialization {
        internal class func vcardDataAppendingPhoto(vcard: Data, photoAsBase64String photo: String) -> Data? {
            let vcardAsString = String(data: vcard, encoding: .utf8)
            let vcardPhoto = "PHOTO;TYPE=JPEG;ENCODING=BASE64:".appending(photo)
            let vcardPhotoThenEnd = vcardPhoto.appending("\nEND:VCARD")
            if let vcardPhotoAppended = vcardAsString?.replacingOccurrences(of: "END:VCARD", with: vcardPhotoThenEnd) {
                return vcardPhotoAppended.data(using: .utf8)
            }
            return nil
    
        }
        class func data(jpegPhotoContacts: [CNContact]) throws -> Data {
            var overallData = Data()
            for contact in jpegPhotoContacts {
                let data = try CNContactVCardSerialization.data(with: [contact])
                if contact.imageDataAvailable {
                    if let base64imageString = contact.imageData?.base64EncodedString(),
                        let updatedData = vcardDataAppendingPhoto(vcard: data, photoAsBase64String: base64imageString) {
                        overallData.append(updatedData)
                    }
                } else {
                    overallData.append(data)
                }
            }
            return overallData
        }
    }
    

    and then you can use it similarly to the existing serialisation method:

    CNContactVCardSerialization.data(jpegPhotoContacts: [contact1, contact2])
    

    Note that this takes care of serialisation, you'll need to write a similar method for deserialisation if you are also importing.

    0 讨论(0)
提交回复
热议问题