1

I am trying to save a contact as a vcf using CNContactVCardSerialization which has worked out relatively well. I did find that apple doesn't include Notes or Images as part of the VCF. I did use a stackoverflow answer to help the images serialized but now I'm struggling with adding notes as well.

Here is what I've tried:

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

    }
    internal class func vcardDataAppendingNote(vcard: Data, note:String) -> Data? {
        let vcardAsString = String(data: vcard, encoding: .utf8)
        let vcardNote = "NOTE:".appending(note)
        let vcardNoteThenEnd = vcardNote.appending("\nEND:VCARD")
        if let vcardNoteAppended = vcardAsString?.replacingOccurrences(of: "END:VCARD", with: vcardNoteThenEnd) {
            return vcardNoteAppended.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.note != "") || contact.imageDataAvailable {
                if contact.imageDataAvailable {
                    if let base64imageString = contact.thumbnailImageData?.base64EncodedString(),
                        let updatedData = vcardDataAppendingPhoto(vcard: data, photoAsBase64String: base64imageString) {
                        overallData.append(updatedData)
                    }
                }

                if contact.note != ""{
                    if let updatedData = vcardDataAppendingNote(vcard: data, note: contact.note){
                        overallData.append(updatedData)
                    }
                }
            } else {
                overallData.append(data)
            }
        }
        return overallData
    }
}

This doesn't seem to be working. I can get either the notes or the images section to work, but not both.

I'm likely not adding to the VCF file properly.

Any help is greatly appreciated.

Prasanth
  • 646
  • 6
  • 21

1 Answers1

1

Its not pretty but here's what I've done and its working for now:

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)
    if let vcardPhotoAppended = vcardAsString?.appending(vcardPhoto) {
        return vcardPhotoAppended.data(using: .utf8)
    }
    return nil

}
internal class func vcardDataAppendingNote(vcard: Data, note:String) -> Data? {
    let vcardAsString = String(data: vcard, encoding: .utf8)
    let vcardNote = "NOTE:".appending(note)
    let vcardFinal = vcardNote.appending("\n")
    if let vcardNoteAppended = vcardAsString?.appending(vcardFinal) {
        return vcardNoteAppended.data(using: .utf8)
    }
    return nil
}

internal class func vcardDataAppendingEnd(vcard: Data) -> Data? {
    let vcardAsString = String(data: vcard, encoding: .utf8)
    let vcardEnd = "\nEND:VCARD"
    if let vcardEndAppended = vcardAsString?.appending(vcardEnd) {
        return vcardEndAppended.data(using: .utf8)
    }
    return nil
}

internal class func vcardDataCleanEnd(vcard: Data) -> Data? {
    let vcardAsString = String(data: vcard, encoding: .utf8)

    if let vcardCleaned = vcardAsString?.replacingOccurrences(of: "END:VCARD", with: "\n"){
        return vcardCleaned.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.note != "") || contact.imageDataAvailable {
            if let updatedData = vcardDataCleanEnd(vcard: data){
                overallData = updatedData
            }
            if contact.note != ""{
                if let updatedData = vcardDataAppendingNote(vcard: overallData, note: contact.note){
                    overallData = updatedData
                }
            }
            if contact.imageDataAvailable {
                if let base64imageString = contact.thumbnailImageData?.base64EncodedString(),
                    let updatedData = vcardDataAppendingPhoto(vcard: overallData, photoAsBase64String: base64imageString) {
                    overallData = updatedData
                }
            }
            if let updatedData = vcardDataAppendingEnd(vcard: overallData){
                overallData = updatedData
            }
        } else {
            overallData.append(data)
        }
    }
    return overallData
}
}
Prasanth
  • 646
  • 6
  • 21