未登录游戏中心时应用程序崩溃

Posted

技术标签:

【中文标题】未登录游戏中心时应用程序崩溃【英文标题】:App crashing when not logged into Game Center 【发布时间】:2015-08-10 15:51:36 【问题描述】:

目前,我的应用会在用户打开应用后立即提示他们登录游戏中心。登录后,他们可以查看自己的成就和排行榜。然而;如果用户拒绝登录游戏中心,然后按下排行榜或成就按钮,整个应用程序就会崩溃。在这种情况下,应用程序应该做的是重新提示用户登录。任何建议将不胜感激。

class viewController: UIViewController, GKGameCenterControllerDelegate 

    var highscore = NSUserDefaults.standardUserDefaults().integerForKey("highscore")
    var loggedin = 1

    override func viewDidLoad() 
        super.viewDidLoad()
        login()
    

    func login() 
        println("Game Center Login Called")
        let localPlayer = GKLocalPlayer.localPlayer()
        loggedin = 2

        // Handle the authentication
        localPlayer.authenticateHandler = (Home: UIViewController!, error: NSError!) -> Void in
            if Home != nil 
                println("Authentication is being processed.")
                self.presentViewController(Home, animated: true, completion: nil)

             else 
                println("Player has been successfully authenticated.")
            
        
    

    func showLeaderboard() 
        let gkScore = GKScore(leaderboardIdentifier: "high_Score_Leader_Board")
        gkScore.value = Int64(highscore)
        GKScore.reportScores([gkScore], withCompletionHandler: (  (error: NSError!) -> Void in
            if (error != nil) 
                // handle error
                println("Error: " + error.localizedDescription);
             else 
                println("Score reported: \(gkScore.value)")
            
        ))

        var gcViewController: GKGameCenterViewController = GKGameCenterViewController()
        gcViewController.gameCenterDelegate = self

        gcViewController.viewState = GKGameCenterViewControllerState.Leaderboards

        gcViewController.leaderboardIdentifier = "high_Score_Leader_Board"
        self.showViewController(gcViewController, sender: self)
        self.presentViewController(gcViewController, animated: true, completion: nil)
    

    @IBAction func gameCenterButtoPressed(sender: AnyObject) 
        if loggedin == 2 
            showLeaderboard()

        

        else 
            login()
        
    

    @IBAction func pointButtonScored(sender: AnyObject) 
       ReportAchievment("testbutton", percentComplete: 100)
    

    func gameCenterViewControllerDidFinish(gcViewController: GKGameCenterViewController!)
    
        self.dismissViewControllerAnimated(true, completion: nil)
    

    func showAchievements() 
        var gcViewController: GKGameCenterViewController = GKGameCenterViewController()
        gcViewController.gameCenterDelegate = self

        gcViewController.viewState = GKGameCenterViewControllerState.Achievements

        self.showViewController(gcViewController, sender: self)
        self.presentViewController(gcViewController, animated: true, completion: nil)
    

    func ReportAchievment(identifier : String, percentComplete : Double)
    
        var achievement = GKAchievement(identifier: identifier)

        if(achievement != nil)
        
            achievement.percentComplete = percentComplete;
            achievement.showsCompletionBanner = true

            GKAchievement.reportAchievements([achievement], withCompletionHandler:  (error : NSError!) -> Void in
                println("Achievement reported")
            )
        
    

    @IBAction func achievementButtonPressed(sender: AnyObject) 

       showAchievements()
    

    override func didReceiveMemoryWarning() 
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    

【问题讨论】:

【参考方案1】:

这是我用来验证 Game Center 玩家身份的代码。您可以在游戏加载时调用checkIfPlayerIsLoggedIn() 函数,该函数将检查玩家是否已登录。如果他们的玩家尚未登录,它将转到loginPlayer() 函数,该函数会尝试登录玩家如果 Game Center 已经设置,如果没有设置,则会显示 Game Center 登录屏幕。如果玩家选择不登录,它将返回一个错误,您可以从那里决定如何处理它(在您的情况下,这可能会告诉用户他们必须登录并尝试再次显示视图控制器)

let localPlayer = GKLocalPlayer.localPlayer()
var delegate: GameCenterInteractorNotifications?
var callingViewController: UIViewController?

func checkIfPlayerIsLoggedIn()

    if (self.localPlayer.authenticated == false)
    
        self.loginPlayer()
     else
    
        self.localPlayer.registerListener(self)
        // Do achievement loading and matchmaking handling here
    


private func loginPlayer()

    self.delegate?.willSignIn()

    self.localPlayer.authenticateHandler = (viewController : UIViewController!, error : NSError!) -> Void in

        if (viewController != nil)
        
            dispatch_async(dispatch_get_main_queue(), 
                self.presentViewController(viewController, animated: true, completion: nil)
            )
        

        else if (self.localPlayer.authenticated == true) // Player signed in
        
            self.localPlayer.registerListener(self)
            self.delegate?.didSignIn()
        

        else // Player did not sign in
        
            self.delegate?.failedToSignIn()
        

        if (error != nil)
        
            println("Failed to sign in with error:\(error.localizedDescription).")
            self.delegate?.failedToSignInWithError(error)
            // Add code to determine what to do with the error
        
    

【讨论】:

扎克的回答真的很棒! +1【参考方案2】:

Zachary 发布了一个很好的 authenticateHandler 示例。我将在他的帖子中补充一些额外的意见:

    像 Zachary 一样,始终检查传递给处理程序的 NSError。如果设置了错误,则 VC 将为 nil。因此,在 OP 的原始代码中,它仅检查是否设置了 VC,错误 + NULL VC 将通过假设用户在实际未登录时已登录的路径。

    检查 NSError 时,error.code ==2 表示用户取消了登录。在 OP 的情况下,他们可能想要专门检查 error.code == 2,然后禁用游戏中无法运行的部分(以及给用户一些关于如何修复它的说明)。

    说到“修复它”,从 ios8.4 开始,没有办法重新显示登录 VC。如果他们取消了它,或者如果游戏中心随机取消了他们的授权(发生这种情况),用户唯一能做的就是终止游戏并完全重新启动它。这将启动一个新的登录序列。

    取消沙盒登录 3 次会永久禁用沙盒访问,需要在相关设备上完全重置。因此,计算(并保存)您看到 error.code == 2 出现的次数并在用户即将锁定其机器时警告用户并不是一个坏主意。(自从沙盒以来不再相关IOS9)

    最后,至少有一个错误设置错误,但localPlayer.authenticated 仍然会报告 YES。一晚我一直工作到凌晨 3 点,试图弄清楚这一点。它并不一致,并且似乎与error.code == -1001(在飞行模式下或网络完全丢失时)更相关。我在这个问题上与 Apple 有一个错误。所以道德是:无论localPlayer.authenticated 说什么,始终检查传递给您的authenticateHandler 的NSerror。

更新 #5:Apple 关闭了我在 #5 上的错误,说这是按预期工作的。 Apple 似乎讨厌告诉用户有什么问题……以至于当您与游戏中心完全没有连接时,您将使用以前缓存的凭据显示为“登录”并显示以前缓存的排行榜。在我看来,这只会让不了解如何登录但实际上无法玩游戏的用户感到沮丧和困惑。

【讨论】:

以上是关于未登录游戏中心时应用程序崩溃的主要内容,如果未能解决你的问题,请参考以下文章

UWP 应用程序在未处于调试模式时崩溃

为啥我的应用程序在尝试登录时崩溃(firebase 登录)

使用 facebook connect 登录后应用程序崩溃

发送邀请后 Google Play 游戏服务崩溃

当我按下一个按钮时我的游戏崩溃了(以 NSException 类型的未捕获异常终止)

取消 Google Play 游戏登录后 Facebook 登录崩溃(反之亦然)