2013-03-14 85 views
1

我正在指导一个七年级和八年级的团队,他们致力于开发一个小应用程序,以大格式显示地址簿中的选项。你可以在callmeapp.org查看他们的一般项目。我们被困在如何提示用户获得许可,以便我们可以访问通讯录。基本上用户提示不能正确显示。仅供参考,我们已经通过设置>常规>重置>重置位置&隐私清除权限。如何获取地址簿权限弹出窗口?

我们正在使用xCode 4.6并在运行6.1.2版本的iPhone MC918LL/A上进行测试。

我们从我们的appdelegate.m didfinishlaunchingwithoptions方法中的DavidPhilipOster的回复代码开始:How do I correctly use ABAddressBookCreateWithOptions method in iOS 6?。我们进行了一些编辑以清除我们正在收到的错误。

现在,应用程序启动到黑屏并在那里停留至少24秒,此时应用程序似乎关闭,显示下面的许可提示。接受将我们发送到桌面。当我们重新打开应用程序时,它的工作就像权限已被清除一样。或者,如果我们在屏幕上显示黑色时按下主屏幕按钮(电话上的一个按钮),则会关闭以显示如上所述的权限提示。 Permisison窗口应在非常短暂的延迟后显示,然后在用户授予许可时将我们留在应用程序中。

我们卡在一些NSLog的观点看看发生了什么。如果有帮助,我已将它们留在代码中。它会显示点1,2,5,然后等待。即使手机显示桌面,清除提示3,7和4后仍然进入。

任何帮助或提示将不胜感激。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 
{ 
    NSLog(@"Point 1"); 
    ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL,NULL); 

    __block BOOL accessGranted = NO; 

    if (ABAddressBookRequestAccessWithCompletion != NULL) { // we're on iOS 6 
     NSLog(@"Point 2"); 
     dispatch_semaphore_t sema = dispatch_semaphore_create(0); 

     ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) { 
      NSLog(@"Point 3"); 
      accessGranted = granted; 
      dispatch_semaphore_signal(sema); 
      NSLog(@"Point 4"); 
     }); 
     NSLog(@"Point 5"); 

     dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); 
     dispatch_release(sema); 
    } else { // we're on iOS 5 or older 
     NSLog(@"Point 6"); 

     accessGranted = YES; 

    } 
    NSLog(@"Point 7"); 

    return YES; 
} 

回答

10

这里的主要问题是,您在应用程序中执行此操作:didFinishLaunchingWithOptions:。总之,这需要转移到另一个地方。 iOS限制了应用程序启动过程中发生的情况 - 以及需要多长时间。对于一个简单的应用程序,您可以将它移到您的主视图控制器中,并在向最终用户显示任何结果之前检查它。

当前,因为您在此方法中使用了信号量,所以它阻止函数返回。 iOS对它等待的时间有严格的限制 - 然后它会杀死应用程序。总之,弹出窗口保持打开 - 但是当你按下OK时 - 应用程序被终止,因为application:didFinishLaunchingWithOptions:方法没有及时完成执行。

另外,我不会在这里推荐信号量方法。有更好的方法来解决这个问题(见下文)。下面的代码只是一个例子。

- (void)setupViewWithContactsData 
{ 
    // Do Something 
} 

- (void)setupViewWithoutContactsData 
{ 
    // Do Something because Contacts Access has been Denied or Error Occurred 
} 

- (void)viewDidLoad 
{ 
    [self checkForAddressBookAccess]; 
} 

- (void)checkForAddressBookAccess 
{ 
    if (ABAddressBookRequestAccessWithCompletion == NULL) 
    { 
     // iOS5 or Below 
     [self setupViewWithContactsData]; 
     return; 
    } 
    else 
    { 
     // iOS6 
     if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusNotDetermined) 
     { 
      ABAddressBookRequestAccessWithCompletion(addressBookRef, ^(bool granted, CFErrorRef error) { 
      if(error) 
        { 
         [self setupViewWithoutContactsData]; 
        } 
        else 
        { 
         [self setupViewWithContactsData]; 
        } 
      }); 
     } 
     else if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusAuthorized) 
     { 
      [self setupViewWithContactsData]; 
     } 
     else 
     { 
      [self setupViewWithoutContactsData]; 
     } 
    } 
} 
+0

谢谢你回答这么快。我试图将它移动到DataViewController didLoad方法,并有同样的麻烦。仅供参考,我们基于我们的应用程序在页面视图应用程序模板。 – EricPerson 2013-03-14 19:40:17

+0

首先 - 信号量方法在这种情况下不是一个好的方法。最好使用异步方法而不是阻塞主线程。看看这个答案:http://stackoverflow.com/questions/12648244/programmatically-request-access-to-contacts-in-ios-6 – dtuckernet 2013-03-14 20:17:37

+0

得到它的工作。感谢您的帮助。秘密是把它放在[super viewDidLoad]行之后。 – EricPerson 2013-03-19 05:27:32