Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/109.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 处理游戏中心身份验证_Ios_Authentication_Game Center_Gamekit - Fatal编程技术网

Ios 处理游戏中心身份验证

Ios 处理游戏中心身份验证,ios,authentication,game-center,gamekit,Ios,Authentication,Game Center,Gamekit,根据协议,我们应该执行以下操作来处理GC身份验证: - (void) authenticateLocalUser { GKLocalPlayer *localPlayer = [GKLocalPlayer localPlayer]; if(localPlayer.authenticated == NO) { [localPlayer setAuthenticateHandler:(^(UIViewController* viewcontroller, N

根据协议,我们应该执行以下操作来处理GC身份验证:

- (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");

            }
        })];

    }
}
我们得到以下信息:

如果设备没有经过身份验证的玩家,游戏套件会将视图控制器传递给您的身份验证处理程序。显示时,此视图控制器显示身份验证用户界面。游戏应暂停需要用户交互的其他活动(如游戏循环),显示此视图控制器,然后返回。当播放器完成与它的交互时,视图控制器将自动关闭

我的问题是,我们如何知道该视图控制器何时被解除,以及如何知道身份验证是否成功


显然,我需要知道身份验证是否有效,如果由于出现magic GC view controller而不得不暂停游戏,我需要知道何时恢复游戏。

您的代码有一个问题:首先,您应该在应用程序加载后立即设置身份验证处理程序。这意味着,无论localPlayer是否经过身份验证,您都可以设置处理程序,以便在播放器注销并再次登录时自动调用该处理程序。如果您的玩家从您的应用程序切换到game center应用程序,并注销/登录,则不会调用应用程序中的处理程序(如果他在应用程序首次启动时已通过身份验证)。设置处理程序的要点是,每次有身份更改(in/out)时,您的应用程序都可以做正确的事情

第二,你不应该依赖错误来做任何事情。即使返回错误,游戏工具包可能仍有足够的缓存信息为您的游戏提供经过身份验证的玩家。这些错误只是为了帮助您进行调试

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

-(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");
}
在我的应用程序中,当应用程序启动时,对AuthenticateLocalLayer的调用仅进行一次。这是因为处理程序在此之后会自动调用

您不知道该视图控制器何时被解除。 文档中的代码示例说明在适当的时间显示视图控制器。这意味着您不必在game center无法登录时每次都显示view controller。事实上,您可能不应该在处理程序中立即显示它。只有当玩家需要继续手头的任务时,才应显示视图控制器。它不应该在一个奇怪的时间出现。这就是我保存视图控制器的原因,这样我可以在以后需要时显示

如果我不得不暂停比赛,我需要知道什么时候恢复比赛,因为 介绍了magic-GC视图控制器

如果将身份验证处理程序设置为根据状态更改发布通知,则可以侦听事件并显示“暂停菜单”或其他内容,直到用户选择继续

我们如何知道身份验证是否成功

如果身份验证成功,则视图控制器为nil,
localPlayer.isAuthenticated
为true

还是不

如果身份验证失败,则
localPlayer.isAuthenticated
为false,并且视图控制器为nil。身份验证失败的原因可能有很多(网络等),在这种情况下,您不应该显示视图控制器,这就是为什么视图控制器将为零。在这种情况下,您应该禁用game center功能,直到用户下次登录。由于身份验证处理程序是自动调用的,因此大多数情况下您不需要执行任何操作。如果您希望提示用户在game center中执行某些操作(您无法通过代码自动执行),则始终可以提供从应用程序启动game center应用程序的方法

编辑:使用类似于
self.isAuthenticated
(如上所述)的标志来跟踪您是否登录不是一个好主意(我不想引起任何混乱,所以我没有删除它)。最好始终检查
[GKLocalPlayer localPlayer].isAuthenticated


编辑:稍微清理了代码-删除了不必要的self.isAuthenticated,并阻止了不需要的变量。

我可能错了,但我认为实际上有一种方法可以知道何时取消验证视图控制器。我相信当用户解除身份验证视图控制器时,将调用您设置的初始身份验证处理程序,但这次处理程序的viewController参数将为nil


我的应用程序的工作方式是:身份验证处理程序在应用程序的开头设置,但身份验证视图控制器仅在用户要求查看排行榜时显示。然后,当取消此身份验证视图控制器时,如果用户已通过身份验证,则初始身份验证处理程序会显示排行榜;如果用户未通过身份验证,则不会显示排行榜。

当Game Center viewController“完成”时,会自动调用Game Center委托方法:“GameCenterViewControllerdFinish”。(这是代理必须使用的方法。)


您可以使用此方法放置应用程序所需的任何内容。

出于某种原因,Game Center authentication view controller是
GKHostedAuthenticationViewController
的一个实例,它是我们不允许使用或引用的私有类。它没有为我们提供任何方法来干净地检测它何时被解除(不同于
GKGameCenterViewController
的实例,它允许我们通过
GKGameCenterControllerDelegate
协议

这个解决方案(阅读解决方案)的工作原理是每四分之一秒在后台测试一次视图控制器被关闭的时间

下面的代码应该是presentingViewController的一部分,它应该符合
GKGameCenterCon
how do we know when this view controller gets dismissed,
// 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
}
// 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
}