ABAddressBookSave is failing without error - ios

I am trying to create a contact group in native by using following code, The Scenario i am trying is : Add any outlook account in native mail then enable contact sync, this will create a contact group. After this if i am trying to create a group from my App then its failing ..
ABAddressBookRef addressBook = ABAddressBookCreate();
ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) {
dispatch_async(dispatch_get_main_queue(), ^{
if (granted) {
CFErrorRef error = NULL;
ABRecordRef worxMailGroup = ABGroupCreate();
BOOL success = ABRecordSetValue(worxMailGroup,kABGroupNameProperty,(__bridge CFTypeRef) #"TestGroup2",&error);
if (success) {
bool bStatus = ABAddressBookAddRecord(addressBook, worxMailGroup, &error);
if (bStatus) {
bStatus = ABAddressBookSave(addressBook, &error);
// bStatus is false and error also nil ..
}
}
}
});
});
Thanks

Related

Creating/Deleting an addressbook group fails in iPad device

I'm trying to manage the contacts of my app by creating a group.
Creating/Deleting a group works fine on simulator (with iOS 11.3 and with iOS 9.3).
In both cases, the default contact settings are set to iCloud in the iOS settings.
I have checked privacy settings in both cases, the permission to access the device contacts was set to YES
The following code fails on iPad with iOS 9.3.5.
-(void) createNewGroup:(NSString*)groupName
{
CFErrorRef error = NULL;
ABAddressBookRef ab = ABAddressBookCreateWithOptions(NULL, &error);
if (ab) {
ABRecordRef newGroup = ABGroupCreate();
ABRecordSetValue(newGroup, kABGroupNameProperty,(__bridge CFTypeRef)(groupName), nil);
ABAddressBookAddRecord(ab, newGroup, &error);
if (error) {
DDLogDebug(#"cannot create group -%#",error);
}else{
ABAddressBookSave(ab, &error);
}
if (error) {
DDLogDebug(#"cannot save group -%#",error);
}
//!!! important - save groupID for later use
self.groupId = ABRecordGetRecordID(newGroup); //-1 for iPad, and for other cases 2,3,4 ....
DDLogDebug(#"createNewGroup : %i",self.groupId );
CFRelease(newGroup);
CFRelease(ab);
}
}
and to delete the group:
Note: I did not test this method on iPad as there is no group that I want to delete, I will test this after I'm able to create a group on the iPad. This method worked as expected on simulator.
-(BOOL)deleteGroup:(NSString *)groupName{
BOOL res;
CFErrorRef error;
ABAddressBookRef ab = ABAddressBookCreate();
NSArray *groups = (__bridge NSArray *) ABAddressBookCopyArrayOfAllGroups(ab);
for (id _group in groups)
{
NSString *currentGroupName = (__bridge NSString*) ABRecordCopyValue((__bridge ABRecordRef)(_group), kABGroupNameProperty);
DDLogDebug(#"group name -%#",currentGroupName);
if ([groupName isEqualToString:currentGroupName])
{
res = ABAddressBookRemoveRecord(ab, (__bridge ABRecordRef)(_group), &error);
return res;
}
}
return NO;
}
I do not get any error but I get the groupID as -1 when trying to create group on iPad, and I check that group isn't created at all.

objective-c Completion Block issue

I am trying to get a JSON (NSString *) of the address book , in async task , however I want it to be asynchronously and with a completion block .
I have managed to retrieve that easy without the completion block , however when I am adding the completion block I have the following compiler error :
Incompatible block pointer types passing NSString *(^)(bool, CFErrorRef)' to parameter of type 'ABAddressBookRequestAccessCompletionHandler' (aka 'void (^)(bool, CFErrorRef)')
here is my code
+ (NSString *) getAddressBook:(id (^)())block {
ABAuthorizationStatus status = ABAddressBookGetAuthorizationStatus();
if (status == kABAuthorizationStatusDenied)
{
// if you got here, user had previously denied/revoked permission for your
// app to access the contacts, and all you can do is handle this gracefully,
// perhaps telling the user that they have to go to settings to grant access
// to contacts
[[[UIAlertView alloc] initWithTitle:nil message:#"This app requires access to your contacts to function properly. Please visit to the \"Privacy\" section in the iPhone Settings app." delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil] show];
return nil;
}
CFErrorRef error = NULL;
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, &error);
if (error)
{
NSLog(#"ABAddressBookCreateWithOptions error: %#", CFBridgingRelease(error));
if (addressBook) CFRelease(addressBook);
return nil;
}
if (status == kABAuthorizationStatusNotDetermined)
{
// present the user the UI that requests permission to contacts ...
ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) -> THE ERROR OCCURS HERE !
{...
I think the problem is within my completion blocks , but I can't find some good example/tutorial for my specific issue I would be really glad if some 1 could help me please.
Your problem is that you are declaring getAddressBook like this(if we strip block)
-(id)block
And you are trying to pass it as a function of type:
-(void)block:(BOOL)aBool error:(CFErrorRef*)error
Blocks are quite hard to get used with syntax(which is improved in swift) however I'm always refering to this site when not sure:
block syntax reference
UPDATE:
You have to actually wait for your async method finish. You may also refer to official documentation
+ (void) getAddressBook:((^)(NSString* result))block {
ABAuthorizationStatus status = ABAddressBookGetAuthorizationStatus();
if (status == kABAuthorizationStatusDenied)
{
// if you got here, user had previously denied/revoked permission for your
// app to access the contacts, and all you can do is handle this gracefully,
// perhaps telling the user that they have to go to settings to grant access
// to contacts
[[[UIAlertView alloc] initWithTitle:nil message:#"This app requires access to your contacts to function properly. Please visit to the \"Privacy\" section in the iPhone Settings app." delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil] show];
block(nil);
}
CFErrorRef error = NULL;
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, &error);
if (error)
{
NSLog(#"ABAddressBookCreateWithOptions error: %#", CFBridgingRelease(error));
if (addressBook) CFRelease(addressBook);
block(nil);
}
if (status == kABAuthorizationStatusNotDetermined)
{
// present the user the UI that requests permission to contacts ...
ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) -> THE ERROR OCCURS HERE !
{
NSString* result = whatever
block(result);
});
}
}
And use it like this:
[YourClass getAddressBook:^(NSString* result)
{
//now you really have result
}];

Execution is stopped with AddressBook Code in iOS during First Install of App

I want to retrieve contacts from AddressBook into my App. The code is having problem for first install, next time onwards it is working fine. For the first installation of App, if AddressBook code executes, the App hangs. After execution of dispatch_semaphore_wait line, the App hangs. I restarted the device, this time App works fine. It is happening if it is first install on new device. How can i fix this?
CFErrorRef * error = NULL;
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, NULL);
__block BOOL isaccess = NO;
if(ABAddressBookRequestAccessWithCompletion != NULL) {
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
//ask to grand or deny access
ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) {
isaccess = granted;
dispatch_semaphore_signal(sema);
});
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
dispatch_release(sema);
}

ABAddressBookRequestAccessWithCompletion iOS 7 and semaphores

this code has been posted before, and been used as well, from what i could gather. i'm in a situation where i need the code to NOT continue until i know if i have access to the contacts.
on Xcode 5.0.2 and iOS 6, this works just fine. on iOS 7, it hangs forever, and then when i kill the app the dialog box comes up asking to allow access to the contacts.
ABAddressBookRef addressBook = ABAddressBookCreate();
__block BOOL accessGranted = NO;
if (ABAddressBookRequestAccessWithCompletion != NULL) { // we're on iOS 6
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) {
accessGranted = granted;
dispatch_semaphore_signal(sema);
});
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
}
else { // we're on iOS 5 or older
accessGranted = YES;
}
in trying to play with this, i then simply set a BOOL to be NO, and then set it to YES within the block. after the block, i put a while loop that checked for the variable being YES, then slept for 1 second. works perfectly fine on 6, on 7 i never reach the NSLog statement in the block, and i'm stuck forever in the while loop printing the log statement.
am i doing something really lame here? or is this method gone haywire on 7?
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, &error);
ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) {
if (granted)
{
self.myAddressBook = addressBook;
}
done = YES;
NSLog(#"in block, done is %#", done ? #"YES" : #"NO");
didGrant = granted;
//dispatch_semaphore_signal(sema);
});
while (!done)
{
NSLog(#"done is %#", done ? #"YES" : #"NO");
sleep(1);
}
I had the same problem, and I realised that the Dialog box that requests access to the contacts blocks the app anyways, so maybe there's a deadlock. So I just ditched the semaphores and did something like this (tested and works on iOS 7.1.1):
ABAddressBookRef addressBook = ABAddressBookCreate();
MyController * __weak weakSelf = self;
if (ABAddressBookRequestAccessWithCompletion != NULL)
{ // we're on iOS 6
if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusNotDetermined)
{
ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) {
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf accessGrantedForAddressBook];
});
});
}
else
if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusAuthorized); //Maybe add something here to handle kABAuthorizationStatusRestricted
[self accessGrantedForAddressBook];
}
}
else // we're on iOS 5 or older
[self accessGrantedForAddressBook];
which is quite similar to what Apple does in their documentation (search for ABAddressBookRequestAccessWithCompletion). Besides, what's the point of ABAddressBookRequestAccessWithCompletion being asynchronous and waiting for it (see here)..

ABAddressBookCopyArrayOfAllPeople wrong on device - right on simulator

I have the following code:
NSMutableArray *contacts = [[NSMutableArray alloc]init];
CFErrorRef *error = nil;
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, error);
if (error)
}
NSArray *arrayOfPeople = (__bridge_transfer NSArray*)ABAddressBookCopyArrayOfAllPeople(addressBook);
It works on the simulator and gives me the expected results - however on the device the number of contacts is 0 and there is no error (the app strangely does not ask me for permissions to access the address book - I even deleted and reinstalled the app)
Any Ideas ?
Thanks in advance
On ios 6 you need get access to the Address Book.
Call ABAddressBookRequestAccessWithCompletion() to get the permission.
see this and AddressHelper
CFErrorRef error = nil;
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, &error);
ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) {
if (error) {
NSLog(#"error %#", error);
}else if (granted){
// Do what you want with the Address Book
}else{
NSLog(#"permission denied");
}
CFRelease(addressBook);
});

Resources