I am using below Code, My application don't ask permission on iOS 6 while on iOS 7 and above version it ask for Contact permission access. On iOS 6 it doesn't show app in privacy setting as well. I have read some other thread but not found any solutions.
App crashed in iOS 6 when user changes Contacts access permissions
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"6.0")) {
__block CDNDeviceContact *controller = self;
// Request authorization to Address Book
ABAddressBookRef addressBookRef = ABAddressBookCreateWithOptions(NULL, NULL);
if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusNotDetermined) {
ABAddressBookRequestAccessWithCompletion(addressBookRef,
^(bool granted, CFErrorRef error) {
if (granted)
[controller loadContacts];
else [controller doAlertForContact];
});
} else if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusAuthorized) {
// The user has previously given access, add the contact
[self loadContacts];
} else {
[controller doAlertForContact];
}
if (addressBookRef) CFRelease(addressBookRef);
}
If the user has previously been presented with the request to get permission, it will not show again. According to the documentation,
The user is only asked for permission the first time you request access. Later calls use the permission granted by the user.
If testing in the simulator, I recommend that you go to iOS Simulator -> Reset Content and Settings so that you are able to simulate the event.
You don't need SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO and you also don't need to create an ABAddressBookRef.
For me, this is works like a charm:
if (ABAddressBookGetAuthorizationStatus) {
switch (ABAddressBookGetAuthorizationStatus()) {
case kABAuthorizationStatusNotDetermined:{
ABAddressBookRequestAccessWithCompletion(self.addressBook, ^(bool granted, CFErrorRef error) {
self.addContactButton.enabled = granted;
if (granted) {
// granted
} else {
// User denied access
}});
} break;
case kABAuthorizationStatusDenied: break;
case kABAuthorizationStatusAuthorized: break;
default: break;
}
}
Related
I am working on Address book in My application,I just want to get an alertview for accessing Address.How Can i show System Generated Alert for accessing addressBook?
If you want to show the user a custom message when asking for permission to use their contacts or address book, instead of the default one shown above, you need to add this field to your Info.plist file:
NSContactsUsageDescription
Here is apple developer link for the same:
https://developer.apple.com/library/ios/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html#//apple_ref/doc/uid/TP40009251-SW14
// Check the authorization status of your application for Address Book
-(void)checkAddressBookAccess
{
switch (ABAddressBookGetAuthorizationStatus())
{
// Update our UI if the user has granted access to their Contacts
case kABAuthorizationStatusAuthorized:
[self showAddressBook];
break;
// Prompt the user for access to Contacts if there is no definitive answer
case kABAuthorizationStatusNotDetermined :
[self requestAddressBookAccess];
break;
// Display a message if the user has denied or restricted access to Contacts
case kABAuthorizationStatusDenied:
case kABAuthorizationStatusRestricted:
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Warning"
message:#"You have not granted access to your contacts or you have revoked it earlier."
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
}
break;
default:
break;
}
}
// Prompt the user for access to their Address Book data
-(void)requestAddressBookAccess
{
TF_Message_View_Controller * __weak weakSelf = self;
ABAddressBookRequestAccessWithCompletion(self.addressBook, ^(bool granted, CFErrorRef error)
{
if (granted)
{
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf showAddressBook];
});
}
});
}
If you wanted to show the alert asking for permission, you can use the following code
This code works with Contacts framework, which is available only for iOS 9.0+
- (void)checkContactStoreAccess {
self.contactsStrore = [[CNContactStore alloc] init];
switch ([CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts]) {
case CNAuthorizationStatusAuthorized: {
[self fetchContactsFromContactStore];
break;
}
case CNAuthorizationStatusNotDetermined:{
[self requestContactsAccess];
break;
}
case CNAuthorizationStatusDenied:
case CNAuthorizationStatusRestricted:{
//show info that access denied for contact and redirect user to settings with
[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]];
}
}
}
- (void)requestContactsAccess {
typeof(self) __weak weakSelf = self;
[self.contactsStrore requestAccessForEntityType:CNEntityTypeContacts completionHandler:^(BOOL granted, NSError * _Nullable error) {
[weakSelf fetchContactsFromContactStore];
}];
}
I am accessing user contacts in iOS.I have called a function which access the user contacts.An alert dialog is shown when this function is called & asking to user allow access to contacts or not.My code works fine if user allow the access.If user don't allow access then i want to again show that dialog of asking permission to user for accessing contacts.I am using following code for accessing the user contacts.Please tel me what to do.
code:
ABAddressBookRef addressBookRef = ABAddressBookCreateWithOptions(NULL, NULL);
if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusNotDetermined)
{
ABAddressBookRequestAccessWithCompletion(addressBookRef, ^(bool granted, CFErrorRef error)
{
NSLog(#"acess:first block");
// First time access has been granted, add the contact
access=[NSUserDefaults standardUserDefaults];
[access setObject:#"false" forKey:#"contact_access"];
[access synchronize];
});
}
else if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusAuthorized)
{
NSLog(#"acess:second block");
// The user has previously given access, add the contact
access=[NSUserDefaults standardUserDefaults];
[access setObject:#"true" forKey:#"contact_access"];
[access synchronize];
}
else
{
NSLog(#"acess:third block");
// The user has previously denied access
// Send an alert telling user to change privacy setting in settings appa
access=[NSUserDefaults standardUserDefaults];
[access setObject:#"false" forKey:#"contact_access"];
[access synchronize];
UIAlertView *alert=[[UIAlertView alloc]initWithTitle:#"Warning" message:#"Please allow access to contacts to use rolodex feature" delegate:self cancelButtonTitle:#"Ok" otherButtonTitles:nil, nil];
[alert show];
}
Unfortunately it's not possible to show the permission popup twice in an iOS application. It's the same strategy for Location, Calendar, Photos, etc.
The possibility you've got is:
on iOS8 and later: Redirect the user on the application setting page, using the deep link provided by UIApplicationOpenSettingsURLString
UIApplication.sharedApplication().openURL(NSURL(string: UIApplicationOpenSettingsURLString)!)
on previous iOS version: Create a popup to warn the user that the application has no access to the contact list, and describe the way to grant access (Go to Setting-> Your App -> Contact ...)
The "allow contacts access" alert that is being shown to user in your app is managed by the system. It's shown once when you initially request access to contacts, user can either permit or deny the access. This alert will never be shown again once user has made a choice. If contacts access has been denied once, the only way to permit access to the contacts then is to go to Settings app and enable access using a switch manually via Contacts section in Privacy tab.
Kindly call this below code in your viewDidLoad method or wherever you want apply this below coding
ABAddressBookRef addressBookRef = ABAddressBookCreateWithOptions(nil, nil);
if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusNotDetermined)
{
ABAddressBookRequestAccessWithCompletion(addressBookRef, ^(bool granted, CFErrorRef error) {
if (granted) {
// If the app is authorized to access the first time then add the contact
}
else
{
// Show an alert here if user denies access telling that the contact cannot be added because you didn't allow it to access the contacts
}
});
}
else if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusAuthorized)
{
// If the user user has earlier provided the access, then add the contact
}
else
{
// If the user user has NOT earlier provided the access, create an alert to tell the user to go to Settings app and allow access
}
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
}];
I am trying to print out all of my phone's contacts to the console, using NSLog(). Currently this code is just printing (null).
.h
#property (nonatomic, strong) NSMutableArray *contactsObjects;
.m
#synthesize contactsObjects;
//lazy instantiation.
- (NSMutableArray *)contactsObjects
{
if(!contactsObjects)
{
contactsObjects = [[NSMutableArray alloc]init];
}
return contactsObjects;
}
- (void)viewWillAppear:(BOOL)animated
{
CFErrorRef error = nil;
// Request authorization to Address Book
ABAddressBookRef addressBookRef = ABAddressBookCreateWithOptions(NULL, &error);
if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusNotDetermined) {
ABAddressBookRequestAccessWithCompletion(addressBookRef, ^(bool granted, CFErrorRef error) {
if (granted) {
// First time access has been granted, add all the user's contacts to array.
CFMutableArrayRef contactsObjects = ABAddressBookCopyArrayOfAllPeople(addressBookRef);
} else {
// User denied access.
// Display an alert telling user that they must allow access to proceed to the "invites" page.
}
});
}
else if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusAuthorized) {
// The user has previously given access, add all the user's contacts to array.
CFMutableArrayRef contactsObjects = ABAddressBookCopyArrayOfAllPeople(addressBookRef);
}
else {
// The user has previously denied access
// Send an alert telling user that they must allow access to proceed to the "invites" page.
}
NSLog(#"%#", contactsObjects);
}
I get two warnings here:
I have no idea what I am supposed to do in order to properly print the names and numbers of my contacts to the console.
How do I print my contacts names and numbers?
You have a scope problem with your code. The contactsObjects variables in viewWillAppear: are not related to the ivar you have called contactsObjects. You're declaring new variables that are using the same name. The NSLog() at the end, on the other hand, is the ivar. But setting those other variables didn't put anything into the ivar, so you see (null), which is how NSLog() represents "no object".
Fix this by not making new variable declarations, but using the ivar.
if (granted) {
contactsObjects = ABAddressBookCopyArrayOfAllPeople(addressBookRef);
else if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusAuthorized) {
contactsObjects = ABAddressBookCopyArrayOfAllPeople(addressBookRef);
You will also need to cast these:
contactsObjects = (__bridge_transfer NSArray *)ABAddressBookCopyArrayOfAllPeople(addressBookRef);
(Also, the function doesn't return a mutable array, so you may have trouble down the road with that.)
The second problem is that ABAddressBookRequestAccessWithCompletion() doesn't stop and wait for its completion Block to run. While access is being requested, the rest of your method carries on, so you reach the NSLog() before contactsObjects is actually set in that case.
You say it prints out null and that you get an error. But this would explain your error.
contactObjects is defined within the if block and the else if block. So by the time you are outside of your conditional it's no longer defined.
Try this
- (void)viewWillAppear:(BOOL)animated
{
CFErrorRef error = nil;
// Request authorization to Address Book
ABAddressBookRef addressBookRef = ABAddressBookCreateWithOptions(NULL, &error);
if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusNotDetermined) {
ABAddressBookRequestAccessWithCompletion(addressBookRef, ^(bool granted, CFErrorRef error) {
if (granted) {
// First time access has been granted, add all the user's contacts to array.
contactsObjects = ABAddressBookCopyArrayOfAllPeople(addressBookRef);
} else {
// User denied access.
// Display an alert telling user that they must allow access to proceed to the "invites" page.
}
});
}
else if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusAuthorized) {
// The user has previously given access, add all the user's contacts to array.
contactsObjects = ABAddressBookCopyArrayOfAllPeople(addressBookRef);
}
else {
// The user has previously denied access
// Send an alert telling user that they must allow access to proceed to the "invites" page.
}
NSLog(#"%#", contactsObjects);
}
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)..