Ios 如何创建要在共享表中使用的vCard/vcf文件?
我不熟悉swift,我发现的方法在我的问题上不受欢迎。我正在构建一个目录应用程序,并从API中提取联系人数据,而不是从手机的通讯簿中 在iOS中,如果您转到通讯簿,您可以选择一个联系人并选择“共享联系人”,这将显示共享表。我想在我的应用程序中使用这个确切的功能 我想我已经弄清楚了共享表,下面是我的代码:Ios 如何创建要在共享表中使用的vCard/vcf文件?,ios,swift,addressbook,abaddressbook,Ios,Swift,Addressbook,Abaddressbook,我不熟悉swift,我发现的方法在我的问题上不受欢迎。我正在构建一个目录应用程序,并从API中提取联系人数据,而不是从手机的通讯簿中 在iOS中,如果您转到通讯簿,您可以选择一个联系人并选择“共享联系人”,这将显示共享表。我想在我的应用程序中使用这个确切的功能 我想我已经弄清楚了共享表,下面是我的代码: @IBAction func actShare(sender: AnyObject) { let activityViewController = UIActivityView
@IBAction func actShare(sender: AnyObject) {
let activityViewController = UIActivityViewController(activityItems: ["text" as NSString], applicationActivities: nil)
presentViewController(activityViewController, animated: true, completion: {})
}
我想将“text”更改为NSString
作为vCard,因为这是iOS从通讯簿中共享的对象,对吗?假设我是对的,我想从我自己的应用程序的联系人对象创建一个vCard,以便将其共享到适当的应用程序(电子邮件、短信等)
如何在Swift中实现这一点?如果我错了,请纠正我,告诉我需要做什么。谢谢
编辑:好的,这是我的更改
@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")
}
及
但是,当我单击“共享”按钮并打开“共享表”时,我选择了要共享的应用程序,但它没有按预期添加/附加联系人数据。如何实现此目的?您可以使用CNContact(需要iOS 9):
这里的技巧是使用
CNContactVCardSerialization.dataWithContacts
将联系人保存到VCard(.vcf)文件,然后将文件URL传递到UIActivityViewController
。活动视图控制器从文件扩展名检测VCard格式,并显示支持该格式的应用程序(如消息、邮件、便笺、空投等)
例如:
@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
}
从iOS应用程序创建联系人并通过网络共享非常简单
外部应用程序
首先,您需要创建共享按钮操作,如下所示:-
-(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];
}
然后可以调用下面的函数,该函数将返回
上述按钮事件中的联系人卡
为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
}
成功的方法:
首先获取所有联系人,然后保存,然后保存make.vcf文件,并在电子邮件、WhatsApp、消息、Skype和iPhone文件中共享.vcf
谢谢-我刚用一个新问题更新了我的初始帖子。不过,我认为你的回答会解决这个问题。我会试试看,然后再打给你。非常感谢!非常感谢你!这非常有效。我现在明白了。不过,我还有最后一个问题。当我共享联系人时,.vcf有一个长名称,如“6DD3C04D-08C1-44C7-8A7E-F08C6F0CB5CD.vcf”。我可以把它改成JohnnyAppleseed.vcf吗,就像你从自己的通讯录中分享联系人一样?编辑:哦,我明白了!我通过附加PathComponent(nsuid().uuiString)忽略了.url。非常感谢你
CNContactFormatter
将在这方面帮助您。我已经更新了代码,向您展示了如何使用它。如果联系人没有姓名(无论出于何种原因),或者如果您一次共享多个联系人(在这种情况下,可能不需要使用第一个姓名),则返回UUID字符串。很高兴提供帮助!请在答案上做标记,就好像它回答了你的问题一样。做得好。。。!只有复制和过去的代码这些方法工作的大部分,但我不能得到一个缩略图或接触图像显示。我收到此错误qltumbnailerrordomain code=0“无法生成缩略图”
Im使用let image=UIImage(名为:“ExistingContactPlaceHolderPic”)contact.imageData=image?.pngData()
有什么想法吗?
-(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];
}
- (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;
}
@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
}
@IBAction func vcfPressed(_ sender: UIButton) {
let arrayContacts = self.fetchAllContacts()
self.saveContactsInDocument(contacts: arrayContacts)
let contact = fetchAllContacts()
do {
try shareContacts(contacts: contact)
}
catch {
}
}
func shareContacts(contacts: [CNContact]) throws {
guard let directoryURL = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first else {
return}
var filename = NSUUID().uuidString
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(data: data, encoding: String.Encoding.utf8))")
try data.write(to: fileURL, options: [.atomicWrite])
let activityViewController = UIActivityViewController(activityItems: [fileURL],applicationActivities: nil)
present(activityViewController, animated: true, completion: {})
}
func fetchAllContacts() -> [CNContact] {
var contacts : [CNContact] = []
let contactStore = CNContactStore()
let fetchReq = CNContactFetchRequest.init(keysToFetch: [CNContactVCardSerialization.descriptorForRequiredKeys()])
do {
try contactStore.enumerateContacts(with: fetchReq) { (contact, end) in
contacts.append(contact)
}}
catch {print("Failed to fetch")}
return contacts
}