2012-09-20 44 views
14

Mi método de recuperación programática de direcciones de correo electrónico desde la Libreta de direcciones ya no parece funcionar en dispositivos con iOS 6. Funcionó en iOS 5 y, curiosamente, todavía funciona en el simulador de iOS 6. ¿Hay alguna forma nueva de recuperar contactos desde la libreta de direcciones de un usuario mediante programación?iOS 6 ¿La libreta de direcciones no funciona?

ABAddressBookRef addressBook = ABAddressBookCreate(); 
CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople(addressBook); 
CFIndex nPeople = ABAddressBookGetPersonCount(addressBook); 

self.contacts = [[NSMutableArray alloc] init]; 

int contactIndex = 0; 
for (int i = 0; i < nPeople; i++) { 
    // Get the next address book record. 
    ABRecordRef record = CFArrayGetValueAtIndex(allPeople, i);   

    // Get array of email addresses from address book record. 
    ABMultiValueRef emailMultiValue = ABRecordCopyValue(record, kABPersonEmailProperty); 
    NSArray *emailArray = (__bridge_transfer NSArray *)ABMultiValueCopyArrayOfAllValues(emailMultiValue); 

    [self.contacts addObject:emailArray]; 
} 

Para aclarar, lo anterior no falla, simplemente no devuelve resultados. ABAddressBookCopyArrayOfAllPeople está vacío. ¡Gracias!

Respuesta

12

Probablemente relacionado con los nuevos controles de privacidad: a partir de iOS 6, en el dispositivo, una aplicación no puede acceder a los contactos del usuario sin su permiso. A partir de la documentación:

En iOS 6.0 y posteriores, si la persona que llama no tiene acceso a la base de datos del libro Dirección:

• Para aplicaciones vinculadas contra iOS 6.0 y versiones posteriores, esta función devuelve NULL.

• Para aplicaciones vinculadas con versiones anteriores de iOS, esta función devuelve una base de datos vacía de solo lectura.

Si usted no ha visto los permisos de alerta venir (“SomeApp quiere acceder a sus contactos”), es posible que las API directos libreta de direcciones simplemente asumir que no tienen acceso y en silencio fallan ; es posible que deba mostrar algo desde el marco AddressBookUI para activarlo.

+2

Sí, tienes razón. Necesita usar ABAddressBookRequestAccessWithCompletion(). ¿Cómo puedo verificar si este método existe (para Keller

52

Creé una clase de ayuda, AddressBookHelper, para manejar la compatibilidad con versiones anteriores. Aquí están las tripas:

-(BOOL)isABAddressBookCreateWithOptionsAvailable { 
    return &ABAddressBookCreateWithOptions != NULL; 
} 

-(void)loadContacts { 
    ABAddressBookRef addressBook; 
    if ([self isABAddressBookCreateWithOptionsAvailable]) { 
     CFErrorRef error = nil; 
     addressBook = ABAddressBookCreateWithOptions(NULL,&error); 
     ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) { 
      // callback can occur in background, address book must be accessed on thread it was created on 
      dispatch_async(dispatch_get_main_queue(), ^{ 
       if (error) { 
        [self.delegate addressBookHelperError:self]; 
       } else if (!granted) { 
        [self.delegate addressBookHelperDeniedAcess:self]; 
       } else { 
        // access granted 
        AddressBookUpdated(addressBook, nil, self); 
        CFRelease(addressBook); 
       } 
      }); 
     }); 
    } else { 
     // iOS 4/5 
     addressBook = ABAddressBookCreate(); 
     AddressBookUpdated(addressBook, NULL, self); 
     CFRelease(addressBook); 
    } 
} 

void AddressBookUpdated(ABAddressBookRef addressBook, CFDictionaryRef info, void *context) { 
    AddressBookHelper *helper = (AddressBookHelper *)context; 
    ABAddressBookRevert(addressBook); 
    CFArrayRef people = ABAddressBookCopyArrayOfAllPeople(addressBook); 

    // process the contacts to return 
    NSArray *contacts = ...  

    [[helper delegate] addressBookHelper:helper finishedLoading:contacts]; 
}; 
+0

Actualizado: se agregó faltante 'CFRelease 'llamadas para evitar la filtración de' AddressBook' en este código. –

+0

Hola, me pregunto por qué la llamada a dispatch_async()? Lo intenté sin él y funciona perfectamente, y tampoco bloquea mi UI mientras la libreta de direcciones se recarga. – jklp

+0

La [documentación] (http://developer.apple.com/library/ios/Documentation/AddressBook/Reference/ABAddressBookRef_iPhoneOS/Reference/reference.html#//apple_ref/doc/uid/TP40007099-CH200-SW17) establece que 'El controlador de finalización se llama en una cola arbitraria. Si su aplicación usa una libreta de direcciones en toda la aplicación, usted es responsable de garantizar que todo el uso de esa libreta de direcciones se envíe a una sola cola para garantizar una operación correcta de seguridad de subprocesos. En las pruebas, tuve algunos bloqueos (no recuerdo) los detalles) que sugirieron problemas de seguridad de subprocesos, lo que me llevó a los documentos. –

12

intento con esto: acceso a la libreta de direcciones debe concederse antes de que pueda ser el acceso mediante programación. Esto es lo que terminé haciendo.

#import <AddressBookUI/AddressBookUI.h> 

    // Request authorization to Address Book 
    ABAddressBookRef addressBookRef = ABAddressBookCreateWithOptions(NULL, NULL); 

    if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusNotDetermined) { 
    ABAddressBookRequestAccessWithCompletion(addressBookRef, ^(bool granted, CFErrorRef error) { 
     // First time access has been granted, add the contact 
     [self _addContactToAddressBook]; 
    }); 
    } 
    else if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusAuthorized) { 
    // The user has previously given access, add the contact 
    [self _addContactToAddressBook]; 
    } 
    else { 
    // The user has previously denied access 
    // Send an alert telling user to change privacy setting in settings app 
    } 
0

probablemente relacionado con los nuevos controles de privacidad, a partir de iOS 6, en el dispositivo, una aplicación no puede acceder a los contactos del usuario sin su permiso.

Código:

-(void)addressBookValidation 
{ 



NSUserDefaults *prefs=[NSUserDefaults standardUserDefaults]; 
ABAddressBookRef addressbook = ABAddressBookCreate(); 
__block BOOL accessGranted = NO; 

if (ABAddressBookRequestAccessWithCompletion != NULL) 
{ 
    if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusNotDetermined) 
    { 
     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); 
     dispatch_release(sema); 
    } 
    else if(ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusAuthorized) 
    { 
     accessGranted = YES; 
    } 
    else if (ABAddressBookGetAuthorizationStatus()==kABAuthorizationStatusDenied) 
    { 
     accessGranted = NO; 
    } 
    else if (ABAddressBookGetAuthorizationStatus()==kABAuthorizationStatusRestricted){ 
     accessGranted = NO; 
    } 
    else 
    { 
     accessGranted = YES; 
    } 


} 
else 
{ 
    accessGranted = YES; 
} 
[prefs setBool:accessGranted forKey:@"addressBook"]; 

NSLog(@"[prefs boolForKey:@'addressBook']--->%d",[prefs boolForKey:@"addressBook"]); 
[prefs synchronize]; 
CFRelease(addressbook); 
} 
Cuestiones relacionadas