Gamekitを使ったiPad - iPhone間のBluetooth通信

Gamekitを使ってBT通信させる場合、その役割は大きくわけて2つ。ServerモードとClientモード。ところが、iPhoneアプリではそれらを明示的に指定することは少なく、Peerという第3のモードが使われることが多い。
なぜならばServer/Clientを用いる場合、ユーザに明示的に選択を求める必要があり、操作が煩雑になりがち。対して、Peerモードは接続時にはServer/Client両方の動作を行い、いざ接続されると自動的にServer/Clientが選択されてうまいことやってくれるという便利なモードだから。さらには、PeerモードならばGKPeerPickerControllerが利用できるので、どれに接続するだとか、接続要求を受け入れるといった部分を簡単に実装可能というメリットもある。その反面、接続が確立するまでに時間がかかるけれども。
iPhone同士の接続ならばお互いの通信内容が対等な場合が多く、その場合Peerモードを使えば簡単にうまいことやってくれる。しかし、iPad-iPhoneだと必ずしも通信内容が対等とは限らない。1台のiPadをServerとし、複数台のiPhoneがClientとして接続するというシーンも想定される。その場合、モードを内部では明示的に指定して接続の処理を行う必要がある。前述のGKPeerPickerControllerが使えなくなるので、接続に伴う処理の流れを把握し、適切なUIをユーザに提供することが求められる。

接続までの処理の流れ

  1. (Server, Client) GKSessionのinitWithSessionID:displayName:sessionMode: メソッドでセッションを生成
    • sessionModeにはそれぞれGKSessionModeServer, GKSessionModeClientを指定
  2. (Server, Client) GKSessionのavailableプロパティをYESにする
    • 接続相手を探しはじめる
  3. (Client) 接続相手をみつけるとGKSessionDelegate のsession:peer:didChangeState: にGKPeerStateAvailableが渡されて上記メソッドが呼ばれる
    • 必要に応じてユーザに接続先を選択させる
  4. (Client) GKSessionのconnectToPeer:withTimeout:メソッドで接続要求をだす
  5. (Server) GKSessionDelegateのsession:didReceiveConnectionRequestFromPeer:が呼ばれるので、GKSessionのacceptConnectionFromPeer:error:なりdenyConnectionFromPeer:なり
  6. (Server, Client) 接続完了したらGKSessionのavailableプロパティをNOに
    • 通信相手を探さない、みつけられない状態になる

通信相手がみつかった、いなくなった、接続中、接続完了というそれぞれのタイミングでGKSessionDelegateのsession:peer:didChangeState:がよばれるのでそこでうまいことハンドリングしてやればいい。接続してしまえば、GKPeerPickerControllerで接続したときと同様にデータの送受信ができる状態となる。