Содержание
В статье рассказывается как реализовать связь нескольких устройств по сети (Wi-Fi или Bluetooth) с помощью GameKit и GKSession. Так как мы используем GameKit, можно сказать что эта статья еще и и о том, как сделать мультиплеер в играх. Для этих же целей можно использовать NSNetService и NSNetServiceBrowser, но они работают как-то странно и не всегда находят устройства в сети, да и поддержку Bluetooth в iOS 5 в NSNetService убрали.
Общие сведения о GKSession
При соеденении через GKSession, iOS сама определяет через что лучше связаться с другим устройством (Bluetooth или Wi-Fi). Но, конечно, можно самому вручную регулировать способ связи, например, включить только Bluetooth и выключить Wi-Fi.
Что же такое GKSession? GKSession — это класс, который выполняет функции поиска других устройств и отправку данных к ним, а так же прием данных с других устройств. GKSession может работать в трех режимах — client, server, peer. Также, GKSession имеет делегат через который уведомляет нас о происходящих событиях.
В режиме Server GKSession позволяет подключать к себе другие устройства, которые работают в режиме Client. Устройства, которые работают в режиме Client не могут «разговаривать» друг с другом, они могут только взаимодействовать с «сервером».
В режиме peer нет центрального устройства с которым связываются все остальные. В такой ситуации каждый сам себе и сервер и клиент для других. В этой статье мы рассмотрим именно такой принцип работы.
В GKSession устройства называются peer и имеют свой ID. Чтобы преобразовать ID пира в «человеческое» имя используется метод:
- (NSString *)displayNameForPeer:(NSString *)peerID;
Состояния устройств
Каждое устройство использующее GKSession имеет определенное состояние. Разберемся в них:
- GKPeerStateAvailable — устройство, которое еще не подключено к сессии, к нему можно подключится
- GKPeerStateUnavailable — устройство, связь с которым прервалась
- GKPeerStateConnected — подключенное устройство
- GKPeerStateDisconnected — устройство, которое отключилось само
- GKPeerStateConnecting — устройство подключается, если имеет такое состояние
GKSessionDelegate
Как было сказано выше, GKSession имеет делегат GKSessionDelegate. Рассмотрим его методы:
- (void)session:(GKSession *)session peer:(NSString *)peerID didChangeState:(GKPeerConnectionState)state;
Уведомляет нас о том, что устройство (peer) peerID сменило свое состояние на state.
- (void)session:(GKSession *)session didReceiveConnectionRequestFromPeer:(NSString *)peerID;
Вызывается, когда устройство peerID хочет к нам подключится. Мы можем принять подключение так:
NSError* error = nil;
[session acceptConnectionFromPeer:peerID error:&error];
Либо отказать в подключении:
[session denyConnectionFromPeer:peerID];
Методы, которые сообщают об ошибках:
- (void)session:(GKSession *)session connectionWithPeerFailed:(NSString *)peerID withError:(NSError *)error;
- (void)session:(GKSession *)session didFailWithError:(NSError *)error;
Также, есть еще метод в который приходят данные от других устройств:
- (void) receiveData:(NSData *)data fromPeer:(NSString *)peer inSession:(GKSession *)session context:(void *)context
Тут data — данные которые к нам пришли. Peer — от кого пришли.
GKSession в действии
Чтобы создать сессию нужно выполнить:
GKSession* session = [[GKSession alloc] initWithSessionID:@"session_id" displayName:nil sessionMode:GKSessionModePeer];
session.delegate = self;
[session setDataReceiveHandler:self withContext:NULL];
session.available = YES;
С помощью @»session_id» устройства узнают друг друга. Чтобы устройства нашли друг друга этот параметр должен быть одинаковый. DisplayName — это имя, которое будут видеть другие устройства, если задать nil — будет использоваться название устройства (то, которое мы можем получить из UIDevice).
После того, как сессия создана уведомления о состоянии устройств мы будем получать в метод:
- (void)session:(GKSession *)session peer:(NSString *)peerID didChangeState:(GKPeerConnectionState)state {
// в зависимости от state решаем, что делать с пиром. Например, можем подключить его:
if ( state == GKPeerStateAvailable ) {
[session connectToPeer:peerID withTimeout:10.0];
}
}
Чтобы отправить данные какому-либо пиру мы можем сделать так:
NSData* data; // данные для отправки
NSArray* peers; // ID пиров, кому отправляем
NSError* error; // ошибка, если будет
[session sendData:data toPeers:peers withDataMode:GKSendDataReliable error:&error];
Тут следует уделить внимание режиму отправки, их два:
- GKSendDataReliable — гарантированная доставка данных, большие порции данных нужно разбивать на более мелкие, может приостановится, если будут неполадки с сетью
- GKSendDataUnreliable — нет гарантии доставки и не гарантируется последовательность данных, но быстро
Примеры
Например, нам нужно подключать всех доступных пиров, обрабатывать их подключение и отключение. Можно сделать так:
- (void)session:(GKSession *)session peer:(NSString *)peerID didChangeState:(GKPeerConnectionState)state {
if ( state == GKPeerStateAvailable ) {
// если кто-то доступен - подключаем
[session connectToPeer:peerID withTimeout:10.0];
} else if ( state == GKPeerStateConnected ) {
// обрабатываем подключение пира
} else if ( state == GKPeerStateDisconnected ) {
// обрабатывает отключение пира
}
}
Если в какой-то момент нужно отправить всем данные:
NSData* data = [@"Hello, Devices!" dataUsingEncoding:NSUTF8StringEncoding];
NSError* error = nil;
[session sendDataToAllPeers:data withDataMode:GKSendDataReliable error:&error];
В таком случае всем пирам будет отправлена строка «Hello, Devices!».
Обрабатываем получение данных (при условии что отправили строку):
- (void) receiveData:(NSData *)data fromPeer:(NSString *)peer inSession:(GKSession *)session context:(void *)context {
NSString* message = [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease];
NSString* name = [session displayNameForPeer:peer];
// в message - сообщение, которое нам прислали,
// в name - имя того, кто отправил
}
На этом все. Как всегда, доступны исходники. По ссылке находится реализация текстового чата между устройствами. Для проверки вам понадобиться как минимум один девайс и симулятор. Скачать тут.
Сообщить об опечатке
Текст, который будет отправлен нашим редакторам: