2016-05-13 13 views
1

私はGameCenter認証を処理するためのスニペットを示すスタックオーバーフローに関する記事を見てきました。しかし、これらのソリューションのいずれも、現実世界のユースケースがカバーする問題のいずれにも対処しません。つまり、[GKLocalPlayer localPlayer] .authenticateHandlerはステータスのコールバックだけであり、あまり多くはありません。これはView Controllerを提供しますが、認証された状態とエラー状態には大規模な不一致があります。GameCenter認証を行う適切な方法は何ですか?

私がやろうとしていますいくつかのことがあります。機能は、アプリの起動 3の上に静かに認証する 2.トライは、ユーザ理由にいくつかの情報を提供し、それを使用するまで 1.ゲームセンターログインをポップアップ表示されませんGameCenterの機能が動作しない 4.復旧メカニズムを提供する

エラーが報告された場合、どうしてログインダイアログを表示するにはどうすればよいですか?

ケース1:

がノーのViewControllerと、このエラーが出るGameCenterManagerで

エラー:: authenticateLocalPlayerは、[インターネット接続がオフラインであるように思われる。]

にもかかわらず、そのエラーメッセージは、デバイスが完全にオンラインになっています。サファリがcnn.comを正常にロードするためです。

ケース2:彼らは準備ができていないので、

誰かがログイン画面を閉じ、ケースが.authenticatedているが、真戻ってくる、のViewControllerはゼロのままで、まだすべてのゲームセンターは失敗します呼び出します。 [GKLocalPlayer localPlayer] .authenticatedがtrueに設定されているのはなぜですか?

ケース3:GameCenterManager :: authenticateLocalPlayer [操作 で

エラーを完了できませんでした。 (NSURLErrorDomainエラー-1009)]

これはまだ発生しますが、アプリケーションはユーザーのために何もできません。この場合、メッセージはどのようなものになりますか?アプリケーションをGame Centerに切り替えてそこにログインしますか?

ケース4:GameCenterManager :: authenticateLocalPlayer [。要求された 操作がキャンセルまたはユーザーによって無効にされている]

ユーザーがアプリのViewControllerをキャンセルした場合、この問題が発生した中

エラーリンゴでプレゼントするように言われました。しかし、この状態を回復または検出することもありません。

ケース5:ローカルプレーヤーが認証されていないので、GameCenterManager :: createMatch [要求された操作で

エラーが 完了できませんでした。]

これはユーザーがログインした場合に発生しますが、何らかの理由でGameCenterからログアウトしてからアプリケーションに戻ります。このアプリは、明らかにそうでないときにユーザーが認証されていると言われますが、別のログインを呼び出すためのコールはありません。

GameCenterが静かに働くだけでなく、アプリケーションデザイナーとして何をするのでしょうか。アラートビューを表示し、ゲームセンターアプリを使用してログインしてアプリを再起動するように指示しますか?ユーザーが認証されていない場合は、一度アプリの起動時に、うまくいけば、有効なログイン状態を作成するために、そして第二、彼らはアプリを使用してみてください:この関数は2回呼び出され

//****************************************************** 
// 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:私はこれにAppleのオープンバグがあります。認証が失敗しても.authenticatedがtrueを返す飛行機モードにあるなど、いくつかのケースがあります。私がこれにバグを書いたとき、Appleはこれが "設計通り"であると言って閉じ、プレイヤーは以前にキャッシュされたデータを使ってゲームを続けることができた。そこで、キャッシュされたデータが重大な問題を引き起こすいくつかのシナリオをバグに追加しました。私のバグは再開され、それ以来そこに座っていました。デザイン哲学は、「まあ、ちょっとしたことがあり、最終的にはすべてがうまくいくかもしれない」と思われる。しかし、それは最終的にはうまくいかない、ユーザーは立ち往生し、プレイすることができず、彼らはアップルではなく私のゲームを責める。

私が見つけた唯一の軽減策は、あなたがすでにやっていることです。常に常に認証ハンドラのNSErrorを確認してください。 View Controllerと.authenticatedは、エラーが設定されていると完全に信頼できません。

エラーが発生した場合は、ユーザーにアラートを表示し、復旧するために必要なことを通知する専用のエラーハンドラに渡します。

ケース3:私は-1009もヒットしました。私が知ることのできるところからは、ネットワークに接続しているときに起こるが、Game Centerは決して答えなかった。これは、ルータが応答していないGame Centerサーバーを含めた間のどこかの混乱から来る可能性があります。 GCテストサーバを使用しているときにこれを多く見ていました。テストサーバーが巧みな環境に統合された今は、そうではありません。

ケース4:100%正確です。ゲーム内の回復はありません。ユーザーが認証をキャンセルすると、それが行末になります。回復する唯一の方法は、ゲームを終了させることです(放置して再入力するのではなく)。次に、それだけで、別のログインビューコントローラを提示することができます。

これを軽減するためにできることがいくつかあります。あなたが確認するまで

  1. は「ゲーム開始」ボタンを無効にする(またはものは何でも、あなたのゲームを持っている):それは直接必要になるまでログインを遅らせるあなたの#1の目標を中断しますが、私はもっと良いもの発見していませんログインに成功し、GCからサンプルリーダーボードを正常にダウンロードできます。これにより、エンドツーエンドの接続性が証明されます。
  2. ユーザーがログインをキャンセルした場合、認証ハンドラはドメインGKErrorDomainとコード= GKErrorCanceledNSErrorを受信します。そのコンボが表示されたら、ネットワークゲームをプレイすることができないことをユーザーに知らせるために、ログインしてログインするまでゲームを停止して再起動する必要があります。
  3. 「スタート」ボタンが無効になった理由をユーザーは混乱していたので、そこで警告を追加しました。私は無効に見えるが本当に有効になっているボタンを表示します。彼らがそれをクリックしようとすると、再びネットワークゲームをするためにゲームセンターにログインする必要があることを知らせる警告が表示されます。

しかし、少なくともユーザーはスタックしていません。

ケース5:これはケース2で言及されたバグで引用した例の1つです。ユーザーが本当にそうでないときにログインしていると考えるようにすることで、最終的に何か悪いことが起こります。

ケース4と同じですが、認証ハンドラがエラーなしで起動し、ネットワークを証明するサンプルのリーダーボードを正常にダウンロードできるまで、セッションを開始できないようにしてください接続。

実際、すべてのコードベースで検索しても、決して.authenticatedを使用することはありません。

これまで述べてきたように、私の認証ハンドラがあります。私はそれがきれいだとは言わないが、これまでのところ、ユーザーは回復不可能な状況に陥っていない。私はそれが絶望的な時代のケースだと思います(クラップスAPIを使って作業する)には絶望的な対策が必要です。

[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

私は、エラーが設定されたポストビューコントローラの場合、アプリを強制終了するための手順を警告表示にポップする必要があります。フィードバックを感謝し、私たちは非常に似たような扱いがあるので、私は悪く感じません。 –

関連する問題