How to create vCard/vcf file to use in share sheet?

半世苍凉 提交于 2019-12-04 08:34:43

问题


I'm new to swift and methods I am finding are deprecated regarding my issue. I'm building a directory app and I'm pulling contact data from an API, not from the phone's address book.

In iOS, if you go to your address book, you can select a contact and choose 'Share Contact' which brings up a share sheet. I want this exact functionality in my app.

I think I've got Share Sheets figured out, and here's my code for that:

    @IBAction func actShare(sender: AnyObject) {

    let activityViewController = UIActivityViewController(activityItems: ["text" as NSString], applicationActivities: nil)
    presentViewController(activityViewController, animated: true, completion: {})
}

I want to to change "text" as NSString to be a vCard, as that is the object that iOS shares from the address book, right? Assuming I'm right, I want to create a vCard from my own app's contact object in order to share it to appropriate apps (email, sms, etc).

How can I achieve that in Swift? If I'm wrong, please correct me and show me what I need to do. Thanks.

EDIT: Okay, here's my changes.

@IBAction func actShare(sender: AnyObject) {
    do {
        var contactData = NSData()
        try contactData = CNContactVCardSerialization.dataWithContacts([createContact()])

        let activityViewController = UIActivityViewController(activityItems: [contactData as NSData], applicationActivities: nil)
        presentViewController(activityViewController, animated: true, completion: {})
    } catch {
        print("CNContactVCardSerialization cannot save address")
    }

and

func createContact() -> CNMutableContact {
    let contactCard = CNMutableContact()
    contactCard.givenName = "John"
    contactCard.familyName = "Doe"
    contactCard.emailAddresses = [
        CNLabeledValue(label: CNLabelWork, value: "john.doe@email.com")
    ]

    return contactCard
}

However, when I click the share button and it brings up my share sheet, I select the application I want to share to and it doesn't add/attach the contact data as intended. How do I accomplish this?


回答1:


The trick here is to save the contact to a VCard (.vcf) file using CNContactVCardSerialization.dataWithContacts, then pass the file URL to the UIActivityViewController. The activity view controller detects the VCard format from the file extension, and shows the apps where the format is supported (e.g. Messages, Mail, Notes, Airdrop, etc)

Example:

@IBAction func buttonTapped(button: UIButton) {

    let contact = createContact()

    do {
        try shareContacts([contact])
    }
    catch {
        // Handle error
    }
}

func shareContacts(contacts: [CNContact]) throws {

    guard let directoryURL = NSFileManager.defaultManager().URLsForDirectory(.CachesDirectory, inDomains: .UserDomainMask).first else {
        return
    }

    var filename = NSUUID().UUIDString

    // Create a human friendly file name if sharing a single contact.
    if let contact = contacts.first where contacts.count == 1 {

        if let fullname = CNContactFormatter().stringFromContact(contact) {
            filename = fullname.componentsSeparatedByString(" ").joinWithSeparator("")
        }
    }

    let fileURL = directoryURL
        .URLByAppendingPathComponent(filename)
        .URLByAppendingPathExtension("vcf")

    let data = try CNContactVCardSerialization.dataWithContacts(contacts)

    print("filename: \(filename)")
    print("contact: \(String(data: data, encoding: NSUTF8StringEncoding))")

    try data.writeToURL(fileURL, options: [.AtomicWrite])

    let activityViewController = UIActivityViewController(
        activityItems: [fileURL],
        applicationActivities: nil
    )

    presentViewController(activityViewController, animated: true, completion: {})
}

func createContact() -> CNContact {

    // Creating a mutable object to add to the contact
    let contact = CNMutableContact()

    contact.imageData = NSData() // The profile picture as a NSData object

    contact.givenName = "John"
    contact.familyName = "Appleseed"

    let homeEmail = CNLabeledValue(label:CNLabelHome, value:"john@example.com")
    let workEmail = CNLabeledValue(label:CNLabelWork, value:"j.appleseed@icloud.com")
    contact.emailAddresses = [homeEmail, workEmail]

    contact.phoneNumbers = [CNLabeledValue(
        label:CNLabelPhoneNumberiPhone,
        value:CNPhoneNumber(stringValue:"(408) 555-0126"))]

    return contact
}




回答2:


You may use a CNContact (requires iOS 9):

let contact = CNMutableContact()
    contact.givenName = "John"
    contact.familyName = "Doe"
    contact.emailAddresses = [
      CNLabeledValue(label: CNLabelWork, value: "john.doe@email.com")
    ]



回答3:


It is very simple to create contact from your iOS app and share over the external apps.

First you need to create Share Button Action like below :-

-(void)shareContactAction:(UIButton*)sender
{  
    CNMutableContact *selectedCon = [[CNMutableContact alloc] init];
    selectedCon.givenName = @"ABC";
    selectedCon.familyName = @"XYZ";
    NSString *phoneNum = @"+91-XXXXXXXXXXX"
    CNLabeledValue *contactNum1 = [CNLabeledValue labeledValueWithLabel:CNLabelHome value:[CNPhoneNumber phoneNumberWithStringValue:phoneNum]];
    selectedCon.phoneNumbers = @[contactNum1];
    NSString *url=[self saveContactDetailsToDocDir:selectedCon];
    UIActivityViewController *activityViewController = [[UIActivityViewController alloc] initWithActivityItems:@[@"Contact", [NSURL fileURLWithPath:url]] applicationActivities:nil];
    [self presentViewController:activityViewController animated:YES completion:nil];     
}

Than you can call the function below which will return the path of the contact card in above button event.

- (NSString *)saveContactDetailsToDocDir:(CNContact *)contact {

    NSArray *paths = NSSearchPathForDirectoriesInDomains (NSDocumentDirectory,     NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString * contactCardPath = [documentsDirectory stringByAppendingString:@"/vCardName.vcf"];
    NSArray *array = [[NSArray alloc] initWithObjects:contact, nil];
    NSError *error;
    NSData *data = [CNContactVCardSerialization dataWithContacts:array error:&error];
    [data writeToFile:contactCardPath atomically:YES];

    return contactCardPath;
}



回答4:


Updated for Swift 4:

@IBAction func buttonTapped(button: UIButton) {

    let contact = createContact()

    do {
        try shareContacts(contacts: [contact])
    }
    catch {
    // Handle error
    }
}

func shareContacts(contacts: [CNContact]) throws {

    guard let directoryURL = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first else {
    return
    }

    var filename = NSUUID().uuidString

    // Create a human friendly file name if sharing a single contact.
    if let contact = contacts.first, contacts.count == 1 {

    if let fullname = CNContactFormatter().string(from: contact) {
        filename = fullname.components(separatedBy: " ").joined(separator: "")
    }
    }

    let fileURL = directoryURL
    .appendingPathComponent(filename)
    .appendingPathExtension("vcf")

    let data = try CNContactVCardSerialization.data(with: contacts)

    print("filename: \(filename)")
    print("contact: \(String(describing: String(data: data, encoding: String.Encoding.utf8)))")

    try data.write(to: fileURL, options: [.atomicWrite])

    let activityViewController = UIActivityViewController(
    activityItems: [fileURL],
    applicationActivities: nil
    )

    present(activityController, animated: true, completion: nil)
}

func createContact() -> CNContact {

    // Creating a mutable object to add to the contact
    let contact = CNMutableContact()

    contact.imageData = NSData() as Data // The profile picture as a NSData object

    contact.givenName = "John"
    contact.familyName = "Appleseed"

    let homeEmail = CNLabeledValue(label:CNLabelHome, value:"john@example.com")
    let workEmail = CNLabeledValue(label:CNLabelWork, value:"j.appleseed@icloud.com")
    contact.emailAddresses = [homeEmail, workEmail]

    contact.phoneNumbers = [CNLabeledValue(
    label:CNLabelPhoneNumberiPhone,
    value:CNPhoneNumber(stringValue:"(408) 555-0126"))]

    return contact
}


来源:https://stackoverflow.com/questions/38335508/how-to-create-vcard-vcf-file-to-use-in-share-sheet

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!