处理Game Centerauthentication

根据苹果文档,我们应该这样做来处理GCauthentication:

- (void) authenticateLocalUser { GKLocalPlayer *localPlayer = [GKLocalPlayer localPlayer]; if(localPlayer.authenticated == NO) { [localPlayer setAuthenticateHandler:(^(UIViewController* viewcontroller, NSError *error) { if (!error && viewcontroller) { DLog(@"Need to log in"); AppDelegate *appDelegate = (AppDelegate*)[[UIApplication sharedApplication] delegate]; [appDelegate.window.rootViewController presentViewController:viewcontroller animated:YES completion:nil]; } else { DLog(@"Success"); } })]; } } 

我们给了这个信息:

如果设备没有authentication播放器,则游戏套件将视图控制器传递给您的authentication处理器。 呈现时,此视图控制器显示authentication用户界面。 你的游戏应该暂停其他需要用户交互的活动(比如你的游戏循环),呈现这个视图控制器然后返回。 当玩家完成与其交互时,视图控制器被自动解除。

我的问题是,我们如何知道这个视图控制器何时被解散,我们如何知道身份validation是否成功?

很明显,我需要知道身份validation是否正常工作,如果因为神奇的GC视图控制器的提示而不得不暂停游戏,我需要知道什么时候恢复游戏。

你的代码有一个问题:首先,你应该尽快设置身份validation处理程序,当你的应用程序加载。 这意味着无论localPlayer是否被authentication,您都可以设置处理程序,以便在玩家注销并重新login时自动调用该处理程序。 如果您的玩家从您的应用切换到游戏中心应用,并注销/进入,则应用中的处理程序将不会被调用(如果应用程序第一次启动时他已经通过身份validation)。 设置处理程序的重点是每当有validation更改(input/输出)时,您的应用程序都可以做正确的事情。

其次,你不应该依赖于任何错误。 即使返回错误,游戏工具包仍可能有足够的caching信息来为游戏提供已authentication的玩家。 错误只是为了协助您进行debugging。

要回答您的问题,请先查看下面的代码示例。

 -(void)authenticateLocalPlayer { GKLocalPlayer *localPlayer = [GKLocalPlayer localPlayer]; //Block is called each time GameKit automatically authenticates localPlayer.authenticateHandler = ^(UIViewController *viewController, NSError *error) { [self setLastError:error]; if (viewController) { self.authenticationViewController = viewController; [self disableGameCenter]; } else if (localPlayer.isAuthenticated) { [self authenticatedPlayer]; } else { [self disableGameCenter]; } }; } -(void)authenticatedPlayer { GKLocalPlayer *localPlayer = [GKLocalPlayer localPlayer]; [[NSNotificationCenter defaultCenter]postNotificationName:AUTHENTICATED_NOTIFICATION object:nil]; NSLog(@"Local player:%@ authenticated into game center",localPlayer.playerID); } -(void)disableGameCenter { //A notification so that every observer responds appropriately to disable game center features [[NSNotificationCenter defaultCenter]postNotificationName:UNAUTHENTICATED_NOTIFICATION object:nil]; NSLog(@"Disabled game center"); } 

在我的应用程序中,只有当应用程序启动时才会调用authenticateLocalPlayer 。 这是因为处理程序在那之后被自动调用。

 how do we know when this view controller gets dismissed, 

你不会知道这个视图控制器何时被解雇。 文档中的代码示例显示在适当的时间显示视图控制器。 这意味着每当游戏中心无法login时,您不一定要显示视图控制器。实际上,您可能不应该立即将其呈现在处理程序中。 只有当玩家有必要继续执行任务时,才应该显示视图控制器。 它不应该在一个奇怪的时间popup。 这就是为什么我保存视图控制器,所以我可以稍后显示时,它是有意义的。

我需要知道什么时候恢复游戏,如果我不得不暂停它,因为神奇的GC视图控制器提交。

如果您将身份validation处理程序设置为根据状态更改发布通知,则可以监听事件并显示“暂停菜单”或其他内容,直到用户select恢复为止。

我们怎么知道validation是否成功

如果authentication成功,则视图控制器为零,并且localPlayer.isAuthenticated为真。

或不 ?

如果身份validation失败,则localPlayer.isAuthenticated为false,视图控制器为零。 鉴于许多原因(networking等),身份validation失败可能发生,在这种情况下,您不应该呈现视图控制器,这就是视图控制器为零的原因。在这种情况下,您应该禁用游戏中心function,直到用户下一次login。由于authentication处理程序是自动调用的,大多数时候你不需要做任何事情。 如果您想要提示用户在游戏中心执行某些操作(通过代码无法自动执行操作),则始终可以提供从应用程序启动游戏中心应用程序的方法。

编辑:使用像self.isAuthenticated (如我上面所做的)标志来跟踪你是否login是不是一个好主意(我不想造成任何困惑,所以我没有删除它) 。 总是检查[GKLocalPlayer localPlayer].isAuthenticated

编辑:清理了一下代码 – 删除了不必要的self.isAuthenticated,并阻止variables不是必需的。

出于某种原因,Game Center身份validation视图控制器是GKHostedAuthenticateViewController一个实例,它是我们不允许使用或引用的私有类。 它不给我们任何方式来干净地检测它何时被解散(不像GKGameCenterViewController实例,它允许我们通过GKGameCenterControllerDelegate协议。

这个解决scheme(阅读解决方法)是在视图控制器被解散的情况下,每隔四分之一秒在后台testing。 这不是很漂亮,但它的工作原理。

下面的代码应该是你的GKGameCenterControllerDelegate一部分,它应该符合GKGameCenterControllerDelegate协议。

提供了Swift和Objective-C。

 // Swift func authenticateLocalUser() { if GKLocalPlayer.localPlayer().authenticateHandler == nil { GKLocalPlayer.localPlayer().authenticateHandler = { (gameCenterViewController: UIViewController?, gameCenterError: NSError?) in if let gameCenterError = gameCenterError { log.error("Game Center Error: \(gameCenterError.localizedDescription)") } if let gameCenterViewControllerToPresent = gameCenterViewController { self.presentGameCenterController(gameCenterViewControllerToPresent) } else if GKLocalPlayer.localPlayer().authenticated { // Enable GameKit features log.debug("Player already authenticated") } else { // Disable GameKit features log.debug("Player not authenticated") } } } else { log.debug("Authentication Handler already set") } } func testForGameCenterDismissal() { dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(0.25 * Double(NSEC_PER_SEC))), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)) { if let presentedViewController = self.presentedViewController { log.debug("Still presenting game center login") self.testForGameCenterDismissal() } else { log.debug("Done presenting, clean up") self.gameCenterViewControllerCleanUp() } } } func presentGameCenterController(viewController: UIViewController) { var testForGameCenterDismissalInBackground = true if let gameCenterViewController = viewController as? GKGameCenterViewController { gameCenterViewController.gameCenterDelegate = self testForGameCenterDismissalInBackground = false } presentViewController(viewController, animated: true) { () -> Void in if testForGameCenterDismissalInBackground { self.testForGameCenterDismissal() } } } func gameCenterViewControllerDidFinish(gameCenterViewController: GKGameCenterViewController!) { gameCenterViewControllerCleanUp() } func gameCenterViewControllerCleanUp() { // Do whatever needs to be done here, resume game etc } 

注意:log.error和log.debug调用引用XCGLogger: https : //github.com/DaveWoodCom/XCGLogger

 // Objective-C - (void)authenticateLocalUser { GKLocalPlayer* localPlayer = [GKLocalPlayer localPlayer]; __weak __typeof__(self) weakSelf = self; if (!localPlayer.authenticateHandler) { [localPlayer setAuthenticateHandler:(^(UIViewController* viewcontroller, NSError* error) { if (error) { DLog(@"Game Center Error: %@", [error localizedDescription]); } if (viewcontroller) { [weakSelf presentGameCenterController:viewcontroller]; } else if ([[GKLocalPlayer localPlayer] isAuthenticated]) { // Enable GameKit features DLog(@"Player already authenticated"); } else { // Disable GameKit features DLog(@"Player not authenticated"); } })]; } else { DLog(@"Authentication Handler already set"); } } - (void)testForGameCenterDismissal { dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.25 * NSEC_PER_SEC)), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{ if (self.presentedViewController) { DLog(@"Still presenting game center login"); [self testForGameCenterDismissal]; } else { DLog(@"Done presenting, clean up"); [self gameCenterViewControllerCleanUp]; } }); } - (void)presentGameCenterController:(UIViewController*)viewController { BOOL testForGameCenterDismissalInBackground = YES; if ([viewController isKindOfClass:[GKGameCenterViewController class]]) { [(GKGameCenterViewController*)viewController setGameCenterDelegate:self]; testForGameCenterDismissalInBackground = NO; } [self presentViewController:viewController animated:YES completion:^{ if (testForGameCenterDismissalInBackground) { [self testForGameCenterDismissal]; } }]; } - (void)gameCenterViewControllerDidFinish:(GKGameCenterViewController*)gameCenterViewController { [self gameCenterViewControllerCleanUp]; } - (void)gameCenterViewControllerCleanUp { // Do whatever needs to be done here, resume game etc } 

我可能是错的,但我认为实际上有一种方法来知道何时authentication视图控制器被解雇。 我相信你设置的初始身份validation处理程序将在用户closures身份validation视图控制器时被调用,除非此时处理程序的viewController参数为零。

我的应用程序的工作方式是:authentication处理程序设置在应用程序的开始处,但authentication视图控制器仅在用户要求查看排行榜时显示。 然后,当这个authentication视图控制器被解散时,初始authentication处理器或者在用户被authentication的情况下显示排行榜,或者如果他不authentication则不显示排行榜。

游戏中心DELEGATE方法:当Game Center viewController为“完成”时,会自动调用“gameCenterViewControllerDidFinish”。 (这是代表的强制性方法。)

你可以把你需要的任何东西放在你的应用程序中。