Salman Ali Salman Ali - 1 year ago 68
Swift Question

Export Picture in VCard Swift

i am trying to develop an app that takes input of some fields from the user about a contact and then export that contact as VCard. I can successfully export the contact but the when i try to import the contact using Contacts at iCloud.com, the picture is not being imported.
All the other information is being imported but not the picture.

There are two ways i tried to export the VCard.

First Way Here

public func getVCard() -> Data?{

var contact = CNMutableContact()

let homeEmail = CNLabeledValue(label:CNLabelHome, value:self.email as! NSString)
contact.emailAddresses = [homeEmail]

let phone = CNLabeledValue(label: CNLabelPhoneNumberMobile, value:CNPhoneNumber(stringValue: self.phone!))
contact.phoneNumbers = [phone]

contact.givenName = self.name!
if let d = self.data{
contact.imageData = d

}


let address = CNMutablePostalAddress()
address.country = self.address!
contact.postalAddresses = [CNLabeledValue(label: CNLabelHome, value: address)]

contact.organizationName = self.company!

contact.jobTitle = title!

let sc1 = CNSocialProfile(urlString: "\(socialMedia1!)", username: self.name!, userIdentifier: self.name!, service: CNContactSocialProfilesKey)
let sc2 = CNSocialProfile(urlString: "\(socialMedia2!)", username: self.name!, userIdentifier: self.name!, service: CNContactSocialProfilesKey)
//contact.socialProfiles = [CNSocialProfile(]
let sc3 = CNSocialProfile(urlString: "\(socialMedia3!)", username: self.name!, userIdentifier: self.name!, service: CNContactSocialProfilesKey)
contact.socialProfiles = [CNLabeledValue(label: "Profile1", value: sc1), CNLabeledValue(label: "Profile2", value: sc2), CNLabeledValue(label: "Profile3", value: sc3)]

contact.note = self.notes!
let urlAddresses = CNLabeledValue(label: CNLabelURLAddressHomePage, value: self.web as! NSString)
contact.urlAddresses = [urlAddresses]

var data: Data?

do{
data = try CNContactVCardSerialization.data(with: [contact])
}catch let error{
print(error.localizedDescription)
}

return data
}


When i debug this function, i can see the picture data in the contact object but when that VCard is exported and i try to import it on iCloud.com it does not import picture of that contact.

Now the second method i used to export the contact is as follow and i would prefer the answer using this method because this is the best fit for me.

func textBasedVCard()-> Data?{

var string = "BEGIN:VCARD\nVERSION:3.0\n"
string += "N:\(self.name!);\nFN:\(self.name!)\nORG:\(self.company!)\nTITLE:\(self.title!)\nTEL;TYPE=WORK,VOICE:\(self.phone!)\nADR;TYPE=WORK:;;\(self.address!)\nNOTE:\(self.notes!)\nitem1.URL:\(self.web!)\nitem2.URL:\(self.blog!)\nitem3.URL:\(self.socialMedia1!)\nitem4.URL:\(self.socialMedia2!)\nitem5.URL:\(self.socialMedia3!)\nEMAIL;TYPE=PREF,INTERNET:\(self.email!)\nEND:VCARD"
print(string)
let utf8str = string.data(using: String.Encoding.utf8)
//utf8str?.base64EncodedStringWithOptions(NSData.Base64EncodingOptions(rawValue: 0))
if let base64Encoded = utf8str?.base64EncodedString(options: .init(rawValue: 0))
{
return Data(base64Encoded: base64Encoded)!

}
return nil
}


In this method i do not know how to attach picture data. Please guide me through this problem. I will be really grateful. Thanks.

Edit:

This question in no way a duplicate of any other question. You can see the link yourself someone posted just to make himself feel proud.

Answer Source

From the response posted above:

Address Book supports vCard version 3.0.

VCARD > PHOTO - An image or photograph of the individual associated with the vCard. It may point to an external URL or may be embedded in the vCard as a Base64 encoded block of text.

2.1: PHOTO;JPEG:http://example.com/photo.jpg
2.1: PHOTO;JPEG;ENCODING=BASE64:[base64-data]
=> 3.0: PHOTO;TYPE=JPEG;VALUE=URI:http://example.com/photo.jpg
=> 3.0: PHOTO;TYPE=JPEG;ENCODING=b:[base64-data]
4.0: PHOTO;MEDIATYPE=image/jpeg:http://example.com/photo.jpg
4.0: PHOTO:data:image/jpeg;base64,[base64-data]

Testing shows the 2nd way works: encode the JPEG photo using base64:

PHOTO;ENCODING=b;TYPE=JPEG:\(self.imageBase64!)

PoC:

struct VCFBuilder {
    private let name: String? = "Name1"
    private let company: String? = "Company"
    private let title: String? = "Title1"
    private let phone: String? = "555-1234-1234"
    private let address: String? = "aaa"
    private let notes: String? = "PROnotes"
    private let web: String? = "web"
    private let blog: String? = "bolgg"
    private let socialMedia1: String? = "social1"
    private let socialMedia2: String? = "social2"
    private let socialMedia3: String? = "social3"
    private let email: String? = "[email protected]"
    private let imageUrl: String? = "http://0.gravatar.com/avatar/3f009d72559f51e7e454b16e5d0687a1"

    func vcf() {

        do {
            let url = URL(string: self.imageUrl!)
            let data = try Data(contentsOf: url!).base64EncodedString()
            let vcf = generateVCF(withEncodedImage: data)
            print(vcf)
        } catch {
            print(error)
        }
    }

    // TODO: Don't !
    private func generateVCF(withEncodedImage imageBase64: String) -> String {
        return """
        BEGIN:VCARD
        VERSION:3.0
        N:\(self.name!);
        FN:\(self.name!)
        ORG:\(self.company!)
        TITLE:\(self.title!)
        TEL;TYPE=WORK,VOICE:\(self.phone!)
        ADR;TYPE=WORK:;;\(self.address!)
        NOTE:\(self.notes!)
        PHOTO;ENCODING=b;TYPE=JPEG:\(imageBase64)
        item1.URL:\(self.web!)
        item2.URL:\(self.blog!)
        item3.URL:\(self.socialMedia1!)
        item4.URL:\(self.socialMedia2!)
        item5.URL:\(self.socialMedia3!)
        EMAIL;TYPE=PREF,INTERNET:\(self.email!)
        END:VCARD
        """
    }
}

VCFBuilder().vcf()
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download