2012年1月29日日曜日

PicTack:iPhoneでBluetooth通信の巻

PicTackでは、Bluetooth or 同一WiFi で端末を接続しマルチプレイを実現しています。
iPhoneでBluetooth接続するには GameKit Frameworkを使用できます。

GameKitは、GameCenterのライブラリ + PeerToPeer接続のライブラリ + Voiceのライブラリ。
今回使用した PeerToPeer接続のライブラリは、ローカルワイヤレスネットワークとBluetooth を行うことができます。

接続は対話式。

Aさん : 接続したい人募集!
Bさん : だれか接続出来る人いないかなー
Bさん : Aさん発見! 接続させてくれー
Aさん : お。Bさんから接続依頼きた。OKですよー
Bさん : お。AさんからOKきた!

みたいな感じ。
接続は 、GKSessionのクラスで管理されて、セッションのID と 端末毎に PeerID が振られます。
通信は NSData型(バイナリ型)で行います。つまり文字列はもちろん、画像とかも送れます。

2台の端末で接続を行う時は、GKPeerPickerController を使うと楽。
接続対象のリストの表示、選択された端末への接続 などの一連の処理を行なってくれるControllerが標準で用意されています。
素敵なサンプルも公開されています (GKTank)

PicTackでは、GKPeerPickerController を使わず、GKSessionという基本のクラスを使って実装しています。
理由は、GKPeerPickerControllerは2台の接続であること。専用のViewが表示されてしまって、ユーザの手順がわずわらしいこと。

後々知ったのですが、「BlueToothが設定ONになっているか?」というのを知るのは private methodを使わないと出来ない。
だけど、このGKPeerPickerControllerを使えばそれもやってくれるみたい。このメリットは大きいですねー。

GKSessionを使う方法をとると、前述の接続も自前でイベントハンドルして処理してあげることになります。

接続方法は、PeerToPeer と Client-Server と Ring の3種類から選べます。

PicTackで選択したのは、ネットワーク負担も軽そうなClient-Server方式。
Appleのドキュメントによると、最大16人まで接続できます。

接続して通信するのは、比較的簡単に実装できます。
"GKSession" でググればたくさん記事が見つかりますので、ここではハマった点を紹介。

BlueToothの設定がONになっているかどうかを判断できない。

Privateメソッドを使えばできるっぽいけど、それをしたら正式にリリースできない。
BluetoothPowerChangedNotification のイベントを取得したらどうにかなる? とチャレンジするもうまくいかず...

そこで、取った方法は、 GKSessionDelegate の didFailWithError でエラーを取得する方法。
#if 0
#define kGKSessionErrorDomain GKSessionErrorDomain
#else
#define kGKSessionErrorDomain @"com.apple.gamekit.GKSessionErrorDomain"
#endif
- (void)session:(GKSession *)session didFailWithError:(NSError *)error {
    if ([[error domain] isEqual:kGKSessionErrorDomain] &&
        ([error code] == GKSessionCannotEnableError)) {
        // Bluetoothもしくは同一WiFiが無い時のエラー
 
    } else {
       //何かのエラー
    }    
}
ただ、このエラーはセッションを作成して開始したタイミングでは飛んでこない。
タイミングをみてavaliableの値を変えるなどしてチェックし直す感じにしました。

また、BlueToothの設定がOFFでもWiFiに接続しているとこのエラーは発生しないのでご注意を。

いつまで経ってもセッションが確立されない時がある

セッションのゴミが残ってしまう時がどうやらあって、そこに接続しようとすると、
> Bさん : Aさん発見! 接続させてくれー
の後に、Aさんから一切応答が無くなるという自体が発生する。

セッションの接続を切って、すぐにまたセッションを開始しようとするとゴミが残るような感じ (ちょっと不明)
ゴミが残ると暫くの間ずーっと残ったままになってしまう。

できたら、ゴミが残るのを避ける対処をしたかったのですが、こうやったら大丈夫! という保証がなかなか出来なかったので、接続できなかったらタイムアウトして他の端末を探すというような事をしました。
この問題は、"ゴミのセッションが残っている" と理解するまでに時間かかってしまってハマリました (;_;)



Bluetooth接続して、描画データの送受信する という所を実装したのは数日でできたのですが、
上記2つを調べるのになんやら色々時間を食ってしまった 感じです。
開発期間を1ヶ月と区切っていたので妥協点も多いのですが... 最悪の事態にはならないように、落ちたりしないように という方向に集中しました。

始めてマルチプレイの画像をtweetしてもらった時は、いやぁ ホント、ホッとしましたww


PicTack
価格 : 無料 (一部のお題は有料)
カテゴリ : ゲーム
対応機種 : iPhone
対応OS : iOS4.1以上
サポートページ : http://pictack.places-inc.com/
リリース日 : ver1.0 2012/01/16


• • •