Как получить данные VCF с изображениями контактов, используя данные CNContactVCardSerializationWithContacts: метод?
Я использую CNContacts и CNContactUI Framework и выбираю контакт через это
CNContactPickerViewController *contactPicker = [CNContactPickerViewController new];
contactPicker.delegate = self;
[self presentViewController:contactPicker animated:YES completion:nil];
а также
-(void)contactPicker:(CNContactPickerViewController *)picker didSelectContact:(CNContact *)contact
{
NSArray *array = [[NSArray alloc] initWithObjects:contact, nil];
NSError *error;
NSData *data = [CNContactVCardSerialization dataWithContacts:array error:&error];
NSLog(@"ERROR_IF_ANY :: %@",error.description);
}
Этот контактный объект имеет contact.imageData и входит в логи. Но когда я попытался перепроверить эти данные
NSArray *contactList = [NSArray arrayWithArray:[CNContactVCardSerialization contactsWithData:data error:nil]];
CNContact *contactObject = [contactList objectAtIndex:0];
Это становится нулевым:
//contactObject.imageData
Почему я получаю этот ноль, и этот контакт имеет изображение при проверке контактов?
3 ответа
В качестве обходного пути вы можете создать поле PHOTO внутри 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];
По некоторым причинам CNContactVCardSerialization не использует ни одной фотографии контакта. VCard после сериализации выглядит так:
BEGIN:VCARD
VERSION:3.0
PRODID:-//Apple Inc.//iPhone OS 9.3.2//EN
N:Contact;Test;;;
FN: Test Contact
END:VCARD
После вставки поля ФОТО в VCard вы получите
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
После этой вставки контакт будет выглядеть нормально в CNContactViewController
Я хотел бы улучшить и модернизировать для Swift 3 отличный ответ от kudinovdenis.
Просто вставьте следующее расширение в ваш проект
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
}
}
и затем вы можете использовать его аналогично существующему методу сериализации:
CNContactVCardSerialization.data(jpegPhotoContacts: [contact1, contact2])
Обратите внимание, что это касается сериализации, вам нужно написать аналогичный метод для десериализации, если вы также импортируете.
Для числа контактов N вы можете добавить данные изображения в VCF, используя простой метод, как показано ниже.
-(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;
}