I am using an application where i want to fetch contacts.The problem is that the app only asks for the first time that app would like to use contacts.Even if i delete the application,clean it and run again,the application is not asking the pop up next time it runs.I debugged the code and found that the permission i gave for the first time is executed.how to solve this.Below is the code i wrote in view did load.
CFErrorRef *error=nil;
ABAddressBookRef addressbook=ABAddressBookCreateWithOptions(NULL, error);
CFArrayRef allpeople=ABAddressBookCopyArrayOfAllPeople(addressbook);
CFIndex npeople=ABAddressBookGetPersonCount( addressbook );
ABAddressBookRef addressBookRef = ABAddressBookCreateWithOptions(NULL, NULL);
if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusNotDetermined) {
ABAddressBookRequestAccessWithCompletion(addressBookRef, ^(bool granted, CFErrorRef error) {
if (granted) {
for ( int i = 0; i < npeople; i++ )
{
ABRecordRef ref = CFArrayGetValueAtIndex( allpeople, i );
NSString *firstName = (__bridge NSString *)(ABRecordCopyValue(ref, kABPersonFirstNameProperty));
NSString *lastName = (__bridge NSString *)(ABRecordCopyValue(ref, kABPersonLastNameProperty));
NSLog(#"Name:%# %#", firstName, lastName); }
// First time access has been granted, add the contact
} else {
// User denied access
// Display an alert telling user the contact could not be added
}
});
}
else if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusAuthorized) {
for ( int i = 0; i < npeople; i++ )
{
ABRecordRef ref = CFArrayGetValueAtIndex( allpeople, i );
NSString *firstName = (__bridge NSString *)(ABRecordCopyValue(ref, kABPersonFirstNameProperty));
NSString *lastName = (__bridge NSString *)(ABRecordCopyValue(ref, kABPersonLastNameProperty));
NSLog(#"Name:%# %#", firstName, lastName); }
// The user has previously given access, add the contact
}
else {
for ( int i = 0; i < npeople; i++ )
{
ABRecordRef ref = CFArrayGetValueAtIndex( allpeople, i );
NSString *firstName = (__bridge NSString *)(ABRecordCopyValue(ref, kABPersonFirstNameProperty));
NSString *lastName = (__bridge NSString *)(ABRecordCopyValue(ref, kABPersonLastNameProperty));
NSLog(#"Name:%# %#", firstName, lastName); }
// The user has previously denied access
// Send an alert telling user to change privacy setting in settings app
}
Follow the following procedure
Go to Device's Setting->General->Reset->Reset Location & Privacy.
Then it should ask you for permission.
Related
I am developing an app using XCode 4.2 and I am trying to create an ABPerson using initWithVCardRepresentation and/or ABPersonCreatePeopleInSourceWithVCardRepresentation , but I can t find a working example . can someone help?
I get the VCard in an NSString format....
Thanks
This is a full example and it works perfectly, it bases on the latest iOS 8.
First of all you should check authorization status and request access right if not, then save the vcard, let just review the code below:
if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusAuthorized){
NSLog(#"Authorized");
[self addVcardsIntoAddressBook:vcard];
} else{
NSLog(#"Not determined");
ABAddressBookRequestAccessWithCompletion(ABAddressBookCreateWithOptions(NULL, nil), ^(bool granted, CFErrorRef error) {
if (!granted){
NSLog(#"Just denied");
return;
}
NSLog(#"Just authorized");
[self addVcardsIntoAddressBook:vcard];
});
}
This is how to add vcard:
- (void)addVcardsIntoAddressBook:(NSData *)vcard {
CFDataRef vCardData = CFDataCreate(NULL, [vcard bytes], [vcard length]);
ABAddressBookRef book = ABAddressBookCreate();
ABRecordRef defaultSource = ABAddressBookCopyDefaultSource(book);
CFArrayRef vCardPeople = ABPersonCreatePeopleInSourceWithVCardRepresentation(defaultSource, vCardData);
for (CFIndex index = 0; index < CFArrayGetCount(vCardPeople); index++) {
ABRecordRef person = CFArrayGetValueAtIndex(vCardPeople, index);
ABAddressBookAddRecord(book, person, NULL);
CFRelease(person);
}
ABAddressBookSave(book, NULL);
}
Here it is Swift version of acoustic's answer;
let vCard : NSData // vcard
let addressBook: ABAddressBook? = ABAddressBookCreateWithOptions(nil, nil)?.takeRetainedValue()
ABAddressBookRequestAccessWithCompletion(addressBook) {
granted, error in
if !granted {
return
}
let vCardData = CFDataCreate(nil, UnsafePointer<UInt8>(vCard.bytes), vCard.length)
let defaultSource = ABAddressBookCopyDefaultSource(addressBook)
let vCardPeople = ABPersonCreatePeopleInSourceWithVCardRepresentation(defaultSource.takeUnretainedValue(), vCardData).takeRetainedValue() as NSArray
for person in vCardPeople {
ABAddressBookAddRecord(addressBook, person, nil)
}
let isSaved = ABAddressBookSave(addressBook, nil)
if isSaved{
//succesfully saved
}
else{
//not saved
}
}
I'm using this code that I found somewhere on a forum:
// Assuming your vCard is stored in vCardString as an NSString
CFDataRef vCardData = (__bridge CFDataRef)[vCardString dataUsingEncoding:NSUTF8StringEncoding];
ABAddressBookRef book = ABAddressBookCreate();
ABRecordRef defaultSource = ABAddressBookCopyDefaultSource(book);
CFArrayRef vCardPeople = ABPersonCreatePeopleInSourceWithVCardRepresentation(defaultSource, vCardData);
CFIndex index = 0;
ABRecordRef person = CFArrayGetValueAtIndex(vCardPeople, index);
I am using it and it is working fine with Vcard 2.1 and 3.0
NSString *filename = [[NSBundle mainBundle] pathForResource:#"Contacts" ofType:#"vcf"];
NSLog(#"openning file %#", filename);
NSData *stringData = [NSData dataWithContentsOfFile:filename];
NSString *vCardString = [[NSString alloc] initWithData:stringData encoding:NSUTF8StringEncoding];
CFDataRef vCardData = (__bridge CFDataRef)[vCardString dataUsingEncoding:NSUTF8StringEncoding];
ABAddressBookRef book = ABAddressBookCreate();
ABRecordRef defaultSource = ABAddressBookCopyDefaultSource(book);
CFArrayRef vCardPeople = ABPersonCreatePeopleInSourceWithVCardRepresentation(defaultSource, vCardData);
for (CFIndex index = 0; index < CFArrayGetCount(vCardPeople); index++) {
ABRecordRef person = CFArrayGetValueAtIndex(vCardPeople, index);
ABAddressBookAddRecord(book, person, NULL);
}
CFRelease(vCardPeople);
CFRelease(defaultSource);
ABAddressBookSave(book, NULL);
CFRelease(book);
I'm trying to copy contacts between my Local contact source and the iCloud contact source and I'm not seeing any results. This code executes without error and seems like it should work, but I don't see the newly created contacts afterward. Anyone see any issues with it?
ABAddressBookRef addressBook = ABAddressBookCreate();
ABRecordRef abSourceSource = ABAddressBookGetSourceWithRecordID(addressBook, kABSourceTypeLocal);
ABRecordRef abDestinationSource = ABAddressBookGetSourceWithRecordID(addressBook, kABSourceTypeCardDAV);
CFArrayRef sourceContacts = ABAddressBookCopyArrayOfAllPeopleInSource(addressBook, abSourceSource);
CFArrayRef destinationContacts = ABAddressBookCopyArrayOfAllPeopleInSource(addressBook, abDestinationSource);
ABPersonCreatePeopleInSourceWithVCardRepresentation(abDestinationSource, ABPersonCreateVCardRepresentationWithPeople(sourceContacts));
ABPersonCreatePeopleInSourceWithVCardRepresentation(abSourceSource, ABPersonCreateVCardRepresentationWithPeople(destinationContacts)));
ABAddressBookSave(addressBook, NULL);
There is a more fundamental problem - you are not calling ABAddressBookGetSourceWithRecordID properly. The 2nd parameter it takes is an int that specifies the record id of a particular source in your address book. You are passing it a constant that describes the type of a particular source.
The constant you are passing, kABSourceTypeCardDav is always 4. However, the record id of the iCloud source in a user's address book can be something very different.
What you need to do is enumerate all the sources and test their types, like so:
NSArray *allSources = (NSArray*)ABAddressBookCopyArrayOfAllSources(addressBook);
for (int i = 0; i < allSources.count; i++) {
ABRecordRef src = [allSources objectAtIndex:i];
NSNumber *stObj = (NSNumber*)ABRecordCopyValue(src, kABSourceTypeProperty);
ABSourceType st = (ABSourceType)[stObj intValue];
if (st == kABSourceTypeCardDAV) {
int recordID = ABRecordGetRecordID(src);
break;
}
}
Then you could use recordID as the argument to the first function
I think you forgot to add the records with ABAddressBookAddRecord. Here is my working example:
ABAddressBookRef addressBook = ABAddressBookCreate();
ABRecordRef abSource = ABAddressBookGetSourceWithRecordID(addressBook, kABSourceTypeLocal);
NSURL *theURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"some.vcf"];
NSData *vCardData = [NSData dataWithContentsOfURL:theURL];
NSLog(#"data %#", vCardData);
NSArray *createdPeople = (__bridge_transfer NSArray*)ABPersonCreatePeopleInSourceWithVCardRepresentation(abSource, (__bridge CFDataRef)vCardData);
NSLog(#"createdPeople %#", createdPeople);
CFErrorRef error = NULL;
bool ok;
for (id person in createdPeople) {
error = NULL;
ok = ABAddressBookAddRecord(addressBook, (__bridge ABRecordRef)person, &error);
if (!ok) {
NSLog(#"add err %#", error);
break;
}
}
if (ok) {
error = NULL;
BOOL isSaved = ABAddressBookSave(addressBook, &error);
if (isSaved) {
NSLog(#"saved..");
}
if (error != NULL) {
NSLog(#"ABAddressBookSave %#", error);
}
}
CFRelease(addressBook);
I would like to list all phone numbers (or any other field) of people in the addressbook.
I've written the following code:
- (void)addressBookFill{
ABAddressBookRef addressBook = ABAddressBookCreate();
people = (NSArray*)ABAddressBookCopyArrayOfAllPeople(addressBook);
[addressBook release];
}
- (void)printAddressBook{
for(id person in people){
NSLog(#"%#", [person class]);
NSLog(#"\t%#", person );
}
}
When I invoke the printAddressBook method I get this on my console:
2010-07-06 10:34:11.998 app[91420:207] __NSCFType
2010-07-06 10:34:11.999 app[91420:207] <CPRecord: 0x5d56ce0 ABPerson>
And I don't have any idea, how to dereference this ABPerson object, how to get any info from it.
I tried:
firstName = ABRecordCopyValue(person, kABPersonFirstNameProperty);
but I got some exceptions.
Can anybody tell me how to get some info from these objects?
Read the documentation about the ABPerson class:
http://developer.apple.com/mac/library/documentation/UserExperience/Reference/AddressBook/Classes/ABPerson_Class/Reference/Reference.html
and also the ABRecord class:
http://developer.apple.com/mac/library/documentation/UserExperience/Reference/AddressBook/Classes/ABRecord_Class/Reference/Reference.html#//apple_ref/occ/cl/ABRecord
[ person valueForProperty: #"propName" ]
You can get the available properties with:
[ ABPerson properties ]
[ EDIT ]
On iPhone, you can use the following code to access a value:
NSString * lastName = (NSString *)ABRecordCopyValue( person, kABPersonLastNameProperty );
May be this code will help you for iOS5, please like it
ABAddressBookRef addressBook = ABAddressBookCreate();
NSArray *arrayOfAllPeople = (__bridge_transfer NSArray *) ABAddressBookCopyArrayOfAllPeople(addressBook);
NSUInteger peopleCounter = 0;
for (peopleCounter = 0;peopleCounter < [arrayOfAllPeople count]; peopleCounter++){
ABRecordRef thisPerson = (__bridge ABRecordRef) [arrayOfAllPeople objectAtIndex:peopleCounter];
NSString *name = (__bridge_transfer NSString *) ABRecordCopyCompositeName(thisPerson);
NSLog(#"First Name = %#", name);
ABMultiValueRef emails = ABRecordCopyValue(thisPerson, kABPersonEmailProperty);
for (NSUInteger emailCounter = 0; emailCounter < ABMultiValueGetCount(emails); emailCounter++){
/* And then get the email address itself */
NSString *email = (__bridge_transfer NSString *)ABMultiValueCopyValueAtIndex(emails, emailCounter);
NSLog(#"Email : %#",email);
}
}
CFRelease(addressBook);
You want get only those contact who has email on my contact so use this code for iOS5
Please like it if it work
First add AddressBook.framework and #import <AddressBook/AddressBook.h>
- (NSArray*)printAddressBook{
NSMutableArray *mutableData = [NSMutableArray new];
ABAddressBookRef addressBook = ABAddressBookCreate();
NSArray *arrayOfAllPeople = (__bridge_transfer NSArray *) ABAddressBookCopyArrayOfAllPeople(addressBook);
NSUInteger peopleCounter = 0;
for (peopleCounter = 0;peopleCounter < [arrayOfAllPeople count]; peopleCounter++){
ABRecordRef thisPerson = (__bridge ABRecordRef) [arrayOfAllPeople objectAtIndex:peopleCounter];
NSString *name = (__bridge_transfer NSString *) ABRecordCopyCompositeName(thisPerson);
NSLog(#"First Name = %#", name);
ABMultiValueRef emails = ABRecordCopyValue(thisPerson, kABPersonEmailProperty);
for (NSUInteger emailCounter = 0; emailCounter < ABMultiValueGetCount(emails); emailCounter++){
/* And then get the email address itself */
NSString *email = (__bridge_transfer NSString *)ABMultiValueCopyValueAtIndex(emails, emailCounter);
NSLog(#"Email : %#",email);
NSMutableDictionary *personDict = [[NSMutableDictionary alloc] initWithObjectsAndKeys:name,#"name",email,#"email", nil];
[mutableData addObject:personDict];
}
}
CFRelease(addressBook);
return [NSArray arrayWithArray:mutableData];
}
I'm trying to get the instant message account information from existing AddressBook contacts on iOS. I walk through the contacts and I get the contacts which have an instant messaging value, but I can't read the jabber-address.
abArray = (NSArray *)ABAddressBookCopyArrayOfAllPeople(ABAddressBookCreate());
for(int i=0 ; i<[abArray count];i++)
{
ABRecordRef record = [abArray objectAtIndex:i];
ABMutableMultiValueRef multi = ABRecordCopyValue(record, kABPersonInstantMessageProperty);
for(CFIndex x=0;x<ABMultiValueGetCount(multi);x++)
{
CFDictionaryRef dict = ABMultiValueCopyValueAtIndex(multi, x);
CFStringRef jabber = CFDictionaryGetValue(dict, kABPersonInstantMessageServiceJabber);
if(CFDictionaryContainsKey(dict, kABPersonInstantMessageServiceJabber))
{
NSLog(#"yes");
}
else {
NSLog(#"no");
}
// only to make it possible to log to console
NSString *jaab = (NSString *)jabber;
NSLog(#"jabber adress: %#" , jaab);
}
CFRelease(dict);
}
}
What am I doing wrong?
for(int i=0 ; i<[abArray count];i++)
{
ABRecordRef record = [abArray objectAtIndex:i];
ABMutableMultiValueRef multi = ABRecordCopyValue(record, kABPersonInstantMessageProperty);
for(CFIndex x=0;x<ABMultiValueGetCount(multi);x++)
{
CFDictionaryRef dict = ABMultiValueCopyValueAtIndex(multi, x);
CFStringRef jabber;
//Use this piece of code to print the dict to log and check
NSDictionary *nsdict = (NSDictionary *)dict;
NSString *jabberID = [NSString stringWithString:#""];
NSLog(#"Dict: %#", nsdict);
if([[nsdict valueForKey:#"service"] isEqualToString:#"Jabber"]){
jabberID = [nsdict valueForKey:#"username"];
}
//Code to print dict to log ends here. Comment the whole piece if not needed.
if(CFStringCompare((CFStringRef)#"jabber", CFDictionaryGetValue(dict, #"service"), 0))
{
NSLog(#"yes");
jabber = CFDictionaryGetValue(dict, #"username");
// only to make it possible to log to console
NSString *jaab = (NSString *)jabber;
NSLog(#"jabber adress: %#" , jaab);
}
else {
NSLog(#"no");
}
}
//CFRelease(dict);
}
I have been able to use the SDK to access Address Book contacts for people, but whenever I pick a contact who is a company, my app crashes.
does anyone know the property for the company field?
does anyone know the code to make it work?
thanks in advance
It seems your issue is not related to company tag itself. AB fields need to be managed carefully, released when not used and checked for nil all the time, many fields are not set.
In principle, here is example of how I use it. This function loads contacts (those fields interested for my app) and returns array with contacts to the caller. Hope this is helpful. Note how I release not needed refs.
- (NSArray *)loadContacts
{
ABAddressBookRef addressBook = ABAddressBookCreate();
CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople(addressBook);
CFIndex nPeople = ABAddressBookGetPersonCount(addressBook);
NSMutableArray *contacts = [NSMutableArray array];
for (int i = 0 ; i < nPeople ; i++ ) {
ABRecordRef person = CFArrayGetValueAtIndex(allPeople, i);
NSString *firstName = ABRecordCopyValue(person, kABPersonFirstNameProperty);
NSString *lastName = ABRecordCopyValue(person, kABPersonLastNameProperty);
NSString *fullName;
if (firstName && lastName) {
fullName = [NSString stringWithFormat:#"%# %#", firstName, lastName];
} else {
if (firstName) {
fullName = [NSString stringWithString:firstName];
} else if (lastName) {
fullName = [NSString stringWithString:lastName];
} else {
continue;
}
}
NSString *email = nil;
ABMultiValueRef emails = ABRecordCopyValue(person, kABPersonEmailProperty);
if (emails) {
NSArray *emailAddresses = [(NSArray *)ABMultiValueCopyArrayOfAllValues(emails) autorelease];
if (emailAddresses && [emailAddresses count] > 0)
email = [emailAddresses objectAtIndex:0];
CFRelease(emails);
}
if (email) {
NSDictionary *contact = [NSDictionary
dictionaryWithObjectsAndKeys:fullName, #"name",
email, #"email", nil];
[contacts addObject:contact];
}
if (firstName)
CFRelease(firstName);
if (lastName)
CFRelease(lastName);
}
CFRelease(allPeople);
CFRelease(addressBook);
return contacts;
}
you need to use kABPersonOrganizationProperty property for get the company name from addressbook