2016-05-13 218 views
1

我在堆棧溢出的帖子中看到了顯示處理GameCenter認證片段的帖子。但是,這些解決方案都不能解決現實世界使用案例涉及的任何問題。也就是說,[GKLocalPlayer localPlayer] .authenticateHandler只是狀態的回調,而不是其他的。它提供了一個視圖控制器,但是在認證和錯誤狀態中存在巨大的不一致。做什麼是GameCenter身份驗證的正確方法?

有我試圖做幾件事情:直到功能使用它 2.嘗試在應用程序啓動默默認證 1.不彈出遊戲中心登錄 3.提供一些信息給用戶爲什麼GameCenter功能不起作用 4.提供恢復機制

即是說如果有錯誤報告我怎麼能顯示登錄對話框呢?

我得到這個錯誤沒有的viewController:

案例1:

錯誤GameCenterManager :: authenticateLocalPlayer [互聯網連接似乎已離線。]

儘管它的錯誤信息,設備完全在線,因爲safari加載cnn.com就好了。

案例2:

有人關閉登錄屏幕,因爲他們還沒有準備好,在這種情況下.authenticated回來爲真,的viewController保持在零,但所有的遊戲中心通話將失敗。爲什麼當[GKLocalPlayer localPlayer] .authenticated設置爲true時不是?

案例3:

錯誤GameCenterManager :: authenticateLocalPlayer [操作 無法完成。 (NSURLErrorDomain error -1009。)]

這種情況持續發生,但應用程序無法爲用戶做任何事情。在這種情況下,消息應該是什麼?將應用程序切換到Game Center並在那裏登錄?

情況4:

錯誤GameCenterManager :: authenticateLocalPlayer [請求的 操作已被取消或由用戶禁用。]

會發生這種情況,如果用戶取消的viewController該應用被告知由蘋果出席。然而,也沒有恢復或檢測到這種狀態。

案例5:

錯誤GameCenterManager :: createMatch [要求的操作因爲 無法完成,因爲本土球員還未被驗證。]

如果用戶已登錄,但無論出於何種原因退出GameCenter然後返回到應用程序,都會發生這種情況。應用程序將被告知用戶仍然通過身份驗證,但顯然不是,但我沒有可以撥打另一個登錄名的電話。所以基本上,如果GameCenter不只是默默地工作,我們應該怎麼做應用程序設計師呢?警報視圖,並告訴他們使用遊戲中心應用程序登錄並重新啓動應用程序?

這裏是我的驗證碼:

//****************************************************** 
// Authenticate 
//****************************************************** 
-(void)authenticateLocalPlayer:(bool)showLogin 
{ 
    if(showLogin && self.loginScreen != nil) 
    { [[WordlingsViewController instance] presentViewController:self.loginScreen animated:YES completion:nil]; } 

    if([GKLocalPlayer localPlayer].isAuthenticated) 
    { 
     NSDLog(NSDLOG_GAME_CENTER,@"GameCenterManager::authenticateLocalPlayer LocalPlayer authenticated"); 
    } 
    __weak GameCenterManager* weakSelf = self; 
    [GKLocalPlayer localPlayer].authenticateHandler = ^(UIViewController *viewController, NSError *error) 
    { 
     if (error != nil) 
     { 
      NSDLog(NSDLOG_GAME_CENTER,@"Error in GameCenterManager::authenticateLocalPlayer [%@]", [error localizedDescription]); 
     } 
     else 
     { 
      if (viewController != nil) 
      { 
       NSDLog(NSDLOG_GAME_CENTER,@"GameCenter: No authentication error, but we need to login"); 
       weakSelf.loginScreen = viewController; 
      } 
      else 
      { 
       if ([GKLocalPlayer localPlayer].authenticated) 
       { 
        NSDLog(NSDLOG_GAME_CENTER,@"GameCenter localPlayer authenticated"); 
        weakSelf.gameCenterAvailable = YES; 
        weakSelf.localPlayer = [GKLocalPlayer localPlayer]; 
        [weakSelf retrieveFriends]; 
        [weakSelf loadPlayerPhoto:weakSelf.localPlayer]; 

        for (id<GameCenterDelegate> listener in weakSelf.listeners) 
        { [listener onPlayerAuthenticated]; } 
       } 
       else 
       { 
        weakSelf.gameCenterAvailable = NO; 
       } 
      } 
     } 
    }; 
} 

這個函數被調用兩次:一次是在應用程序啓動,希望能夠建立一個有效的登錄狀態,第二如果用戶沒有通過驗證,他們嘗試使用一個應用程序功能需要遊戲中心。在這個應用程序,它正在創建一個基於回合的比賽或查看朋友

回答

2

你遇到了很多我對Game Center API的抱怨。我一直在努力實現你的4件事。 TL; DR版本:Game Center根本不支持它。 > <但您可以採取一些措施來減輕疼痛。

一個一般的事情,幫助我:一定要檢查NSError以及它的.underlyingError屬性。我見過幾種情況,其中NSError太模糊而無法幫助,但底層錯誤具有更具體的細節。

案例1:你能分享NSError和underlyingError的錯誤域和錯誤碼嗎?案例2:我有一個與蘋果公司有關的這個開放的bug,一個懶惰的時間。有幾種情況,包括處於飛行模式,其中身份驗證失敗,但.authenticated返回true。當我爲此寫了一個bug時,蘋果公司關閉了它,說這是「設計上的」,所以玩家可以繼續使用任何以前緩存的數據玩遊戲。所以,我在緩存的數據導致嚴重問題的幾種情況下追加了該錯誤。我的錯誤被重新打開,並一直坐在那裏。設計理念似乎是:「好吧,繼續下去,也許它最終都會奏效。」但它最終無法實現,用戶被卡住了,無法玩,他們責怪我的遊戲,而不是蘋果。

我發現的唯一緩解措施就是您已經在做的事情:始終始終在驗證處理程序中首先檢查NSError。如果設置了錯誤,視圖控制器和.authenticated是完全不可靠的。

如果出現錯誤,我將它傳遞給一個專門的錯誤處理程序,該錯誤處理程序向用戶顯示警報,並告知他們需要執行哪些恢復操作。

案例3:我也擊中了-1009。從我可以看出它發生在我有網絡連接時,但Game Center從未回覆。這可能來自我的路由器之間的任何中斷,包括沒有響應的Game Center服務器。使用GC測試服務器時,我經常看到這一點。現在沒有那麼多,測試服務器被合併到產品環境中。

案例4:你100%正確。沒有遊戲中的恢復。如果用戶取消了認證,那就是行的末尾。要恢復的唯一方法是殺死遊戲(不只是離開並重新進入)並重新啓動它。然後,只有這樣,您纔可以呈現另一個登錄視圖控制器。

雖然有些事情可以減輕這一點。它會直接關閉,直到需要延遲登錄您的#1的目標,但我還沒有找到更好的東西:

  1. 禁用「開始遊戲」按鈕(或任何你在你的遊戲),直到你確定登錄成功,沒有錯誤,並且您可以成功從GC下載示例排行榜。這證明了端到端的連接性。
  2. 如果用戶取消登錄,您的身份驗證處理程序將收到一個NSError的域= GKErrorDomain和代碼= GKErrorCanceled。當我看到這個組合時,我向用戶發出警告,告訴他們在成功登錄和登錄之前不能玩網絡遊戲,他們必須停止並重新開始遊戲。
  3. 用戶很困惑,爲什麼「開始」按鈕被禁用,所以我也在那裏添加了一個提醒。我顯示一個看起來被禁用但真正啓用的按鈕。當他們嘗試點擊它時,我再次發出警告,告訴他們必須登錄遊戲中心才能玩網絡遊戲。

它很爛,但至少用戶沒有卡住。案例5:這是我在案例2中引用的我的錯誤中引用的例子之一。通過讓用戶認爲他們登錄時他們確實沒有,他們試圖做他們真正可以'不要做,最終會發生不好的事情。

我發現的最好的緩解措施與案例4相同:不要讓用戶開始會話,直到您看到身份驗證處理程序觸發且沒有錯誤,並且您可以成功下載示例排行榜來證明網絡連接。

事實上,通過我所有的代碼庫進行搜索,我從來沒有使用.authenticated任何決定了。

說了這麼多,這裏是我的身份驗證處理程序。我不會說這很漂亮,但到目前爲止,用戶不會陷入無法恢復的情況。我想這是一個絕望的時代(使用垃圾API)需要絕望的措施(kludgy解決方法)。

[localPlayer setAuthenticateHandler:^(UIViewController *loginViewController, NSError *error) 
{ 
    //this handler is called once when you call setAuthenticated, and again when the user completes the login screen (if necessary) 
    VLOGS (LOWLOG, SYMBOL_FUNC_START, @"setAuthenticateHandler completion handler"); 

    //did we get an error? Could be the result of either the initial call, or the result of the login attempt 
    if (error) 
    { 
     //Here's a fun fact... even if you're in airplane mode and can't communicate to the server, 
     //when this call back fires with an error code, localPlayer.authenticated is set to YES despite the total failure. >< 
     //error.code == -1009 -> authenticated = YES 
     //error.code == 2 -> authenticated = NO 
     //error.code == 3 -> authenticated = YES 

     if ([GKLocalPlayer localPlayer].authenticated == YES) 
     { 
      //Game center blatantly lies! 
      VLOGS(LOWLOG, SYMBOL_ERROR, @"error.code = %ld but localPlayer.authenticated = %d", (long)error.code, [GKLocalPlayer localPlayer].authenticated); 
     } 

     //show the user an appropriate alert 
     [self processError:error file:__FILE__ func:__func__ line:__LINE__]; 

     //disable the start button, if it's not already disabled 
     [[NSNotificationCenter defaultCenter] postNotificationName:EVENT_ENABLEBUTTONS_NONETWORK object:self ]; 
     return; 
    } 

    //if we received a loginViewContoller, then the user needs to log in. 
    if (loginViewController) 
    { 
     //the user isn't logged in, so show the login screen. 
     [appDelegate presentViewController:loginViewController animated:NO completion:^ 
      { 
       VLOGS(LOWLOG, SYMBOL_FUNC_START, @"presentViewController completion handler"); 

       //was the login successful? 
       if ([GKLocalPlayer localPlayer].authenticated) 
       { 
        //Possibly. Can't trust .authenticated alone. Let's validate that the player actually has some meaningful data in it, instead. 
        NSString *alias = [GKLocalPlayer localPlayer].alias; 
        NSString *name = [GKLocalPlayer localPlayer].displayName; 
        if (alias && name) 
        { 
         //Load our matches from the server. If this succeeds, it will enable the network game button 
         [gameKitHelper loadMatches]; 
        } 
       } 
      }]; 
    } 

    //if there was not loginViewController and no error, then the user is already logged in 
    else 
    { 
     //the user is already logged in, so load matches and enable the network game button 
     [gameKitHelper loadMatches]; 
    } 

}]; 
+0

正如預期的那樣,我想我將不得不彈出一個警告視圖,帶有指示在視圖控制器出錯的情況下殺死應用程序。欣賞反饋,看起來我們有非常類似的處理,所以我不覺得糟糕。 –

相關問題