I have the following code that I have been using before to handle invitations:
[GKMatchmaker sharedMatchmaker].inviteHandler = ^(GKInvite *acceptedInvite, NSArray *playersToInvite) {
// Insert game-specific code here to clean up any game in progress.
if (acceptedInvite) {
GKMatchmakerViewController *mmvc = [[GKMatchmakerViewController alloc] initWithInvite:acceptedInvite];
mmvc.matchmakerDelegate = self;
[self presentViewController:mmvc animated:YES completion:nil];
}
};
However, now it has become deprecated in iOS 7
. Where and how do I register a GameKit invite handler in my project?
GKInviteEventHandler to the rescue, and in particular take a look at GKLocalPlayerListener.
Conform to the GKLocalPlayerListener
protocol and you should be OK. Below are the protocol methods, which look to be the intended replacement for invitationHandler, but split up in two parts.
- (void)player:(GKPlayer *)player didAcceptInvite:(GKInvite *)invite
- (void)player:(GKPlayer *)player didRequestMatchWithPlayers:(NSArray *)playerIDsToInvite
After you set up some object to conform to that, you just make a call to registerListener:
.
[[GKLocalPlayer localPlayer] registerListener:yourObjectHere]
Don't worry about registering it as soon as possible, as the system caches the invites/challenges/turn based stuff, if there's no one to handle those and lets your listener know as soon as you set it up.
As Sam says the new way to do this is with the GKLocalPlayerListener protocol. The approach is reversed now. In the past you issued invitations to other players from part of your app. The other part listened for an invitation from another player and responded to that. Now, you use a matchMakerViewController or Game Center to issue invitations (as before) but now you listen for the acceptance of those invitations. After that Game Center calls didFindMatch to get everything started. If you are in receipt of an invitation Game Center starts your game and then calls didFindMatch to start it up.
This is my code:
In my .h file the GKLocalPlayerListener protocol:
@interface MNFStartupViewController : UIViewController<ADBannerViewDelegate, GKMatchmakerViewControllerDelegate, GKMatchDelegate, GKLocalPlayerListener, UIAlertViewDelegate>
in the .m file in my authenticateHandler block after the local player is authenticated:
[[GKLocalPlayer localPlayer] registerListener:self];
Then the method to listen for the acceptance of an invite:
-(void)player:(GKPlayer *)player didAcceptInvite:(GKInvite *)invite{
//Called when another player accepts a match invite from the local player.
NSLog(@"didAcceptInvite was called: Player: %@ accepted our invitation", player);
GKMatchmakerViewController *mmvc = [[GKMatchmakerViewController alloc] initWithInvite:invite];
mmvc.matchmakerDelegate = self;
[self presentViewController:mmvc animated:YES completion:nil];}
Now the method to start the game from Game Center with a set of players chosen in Game Center. This is hard to debug because you cannot start the game in Game Center whilst running it from Xcode at the same time (I don't think so anyway!) so there is a debugging AlertView that can be dropped.
-(void)player:(GKPlayer *)player didRequestMatchWithPlayers:(NSArray *)playerIDsToInvite{
//Called when the local player starts a match with another player from Game Center
//Start of debugging logging and alerting
NSLog(@"In didRequestMatchWithPlayers for players: %@", playerIDsToInvite);
NSString *logString = [[NSString alloc] initWithFormat:@"didrequestMatchWithPlayers was called with player IDs: %@", playerIDsToInvite];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Logging Alert" message:logString delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
[alert show];
//End of debugging logging and alerting
//Create a match for the chosen players
GKMatchRequest *match = [[GKMatchRequest alloc]init];
match.playersToInvite = playerIDsToInvite;
//Create a matchmaking viewcontroller for that match
GKMatchmakerViewController *mmvc = [[GKMatchmakerViewController alloc]initWithMatchRequest:match];
mmvc.matchmakerDelegate = self;
[self presentViewController:mmvc animated:YES completion:nil];}
This is a method to kick off the whole matchmaking process:
-(IBAction)setupMatch:(id)sender{
GKMatchmakerViewController *matchViewController = [[GKMatchmakerViewController alloc] initWithMatchRequest:matchRequest];
matchViewController.matchmakerDelegate = self;
[self presentViewController:matchViewController animated:YES completion:nil];}
Finally this is the method called by Game Center to set the match going when all the players are connected and ready to go. currentPlayer, currentMatch and hostingPlayer are my own properties with obvious uses.
-(void)matchmakerViewController:(GKMatchmakerViewController *)viewController didFindMatch:(GKMatch *)match{
//Called when GameCenter completes the auto matchmaking process
match.delegate = (id)self;
[self setCurrentMatch:match];
[self setCurrentPlayers:match.playerIDs];
NSLog(@"Match was found with players: %@, time to get on with the game.", self.currentPlayers);
//Use the built in features to decide which device should be the server.
self.hostingPlayer = [self chooseHostingPlayerIDfromPlayerIDs:self.currentPlayers];
[self dismissViewControllerAnimated:YES completion:nil];}
Hope it helps.
Also, invites only work on the devices. I could not get invites to work in the simulator in iOS 8.1.
I believe the answer is, annoyingly, different for a GKMatch
and a GKTurnBasedMatch
.
For a GKTurnBasedMatch
the invitation counts as a turn event, and is handled in this function:
player(_ player: GKPlayer, receivedTurnEventFor match: GKTurnBasedMatch, didBecomeActive: Bool)
That's inside the GKLocalPlayerListener
protocol. You have to have officially registered GKLocalPlayerListener
instance with your local player for this to work, so you can only do it after authentication.
...and it doesn't always work. Game Center is unreliable. But it does work sometimes, and that's... something?