Handling Game Center authentication

前端 未结 4 1895
情书的邮戳
情书的邮戳 2021-02-06 13:41

According to the Apple docs we should do something like this to handle GC authentication:

- (void) authenticateLocalUser
{
    GKLocalPlayer *localPlayer = [GKLo         


        
4条回答
  •  野性不改
    2021-02-06 14:34

    For some reason, the Game Center authentication view controller is an instance of GKHostedAuthenticateViewController which is a private class we're not allowed to use or reference. It doesn't give us any way to cleanly detect when it is dismissed (unlike instances of GKGameCenterViewController which allow us to via the GKGameCenterControllerDelegate protocol.

    This solution (read workaround) works by testing in the background every quarter of a second for when the view controller has been dismissed. It's not pretty, but it works.

    The code below should be part of your presentingViewController, which should conform to the GKGameCenterControllerDelegate protocol.

    Swift and Objective-C provided.

    // 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
    }
    

    Note: the log.error and log.debug calls are referencing 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
    }
    

提交回复
热议问题