GKMatchMaker invite handler deprecated - ios

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?

Related

GKLocalPlayerListener protocol is not called

As the apple guidelines said; I've implemented the GKLocalPlayerListener protocol in my game center class and add the local player as listener as soon as he's authenticated:
func authenticationChanged() {
if (GKLocalPlayer.localPlayer().authenticated && !self.userAutenticated) {
println("Authentication changed: player authenticated.")
userAutenticated = true
GKLocalPlayer.localPlayer().unregisterAllListeners()
GKLocalPlayer.localPlayer().registerListener(self)
} else if (GKLocalPlayer.localPlayer().authenticated && self.userAutenticated) {
println("Authentication changed: player not authenticated.")
userAutenticated = false
}
}
Protocol implementation:
// MARK: - GKLocalPlayerListener
func player(player: GKPlayer!, didAcceptInvite invite: GKInvite!) {
println("Did accept invite")
}
func player(player: GKPlayer!, didRequestMatchWithRecipients recipientPlayers: [AnyObject]!) {
println("Did request matchmaking")
}
None of this 2 methods it's called when I try to invite a friend and I also didn't receive any kind of notifications.
I've tried to test the game in release mode but I've got the same result.
I must say the the normal matchmaking works correctly, I'm able to find player to play with without any problems.
EDIT:
If i test test it from 2 devices, the notification will be received but if i tap on the notification, the app will be open and no delegate will be called. If i close the app and restart it again, then the GKLocalPlayerListener it's called.
What's wrong??
I assume that, when you say "the normal matchmaking works" that you have presented a matchmakerviewcontroller:
-(IBAction)setupMatch:(id)sender{
GKMatchmakerViewController *matchViewController = [[GKMatchmakerViewController alloc] initWithMatchRequest:matchRequest];
matchViewController.matchmakerDelegate = self;
[self presentViewController:matchViewController animated:YES completion:nil];}
Then when the players are found in the matchmakerviewcontroller didFindMatch will be called:
-(void)matchmakerViewController:(GKMatchmakerViewController *)viewController didFindMatch:(GKMatch *)match{
//Called when GameCenter completes the matchmaking process
match.delegate = (id)self; //etc. lots of your own code here.
didAcceptinvite is only called on the device of the recipient of an invite after they accept the invite:
-(void)player:(GKPlayer *)player didAcceptInvite:(GKInvite *)invite{
//Called on the accepting device when the invitation is accepted
GKMatchmakerViewController *mmvc = [[GKMatchmakerViewController alloc] initWithInvite:invite];
mmvc.matchmakerDelegate = self;
[self presentViewController:mmvc animated:YES completion:nil];
}
That presents a matchmakerviewcontroller to your friend. There is nothing for them to do, the vc makes the connection and then dismisses itself. The vc on the senders device dismisses at the same time.
Then didFindMatch is called on both devices and away you go.
I am not convinced didrequestMatchWithRecipients is ever called and it seems redundant when didFindMatch and didAcceptInvite deal with the game start at both ends.
I found this video from WWDC 2012 really helpful: WWDC 2012 Christy Warren

Is it possible to find the numbers user sent SMS to in cocoa touch?

I'm using below code to send sms. We want to find the numbers user is sending text and give them free credit. I just wonder if it is possible to get the numbers which user sent text to.
-(IBAction)promotionSms{
if(![MFMessageComposeViewController canSendText]) {
UIAlertView *warningAlert = [[UIAlertView alloc] initWithTitle:#"Error" message:#"Your device doesn't support SMS!" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[warningAlert show];
return;
}
NSString *message = [NSString stringWithFormat:#"Text Here"];
MFMessageComposeViewController *messageController = [[MFMessageComposeViewController alloc] init];
messageController.messageComposeDelegate = self;
[messageController setBody:message];
// Present message view controller on screen
[self presentViewController:messageController animated:YES completion:nil];
}
- (void)messageComposeViewController:(MFMessageComposeViewController *)controller didFinishWithResult:(MessageComposeResult)result
{
[self dismissViewControllerAnimated:YES completion:nil];
if (result == MessageComposeResultCancelled)
NSLog(#"Message cancelled");
else if (result == MessageComposeResultSent)
NSLog(#"Message sent");
else
NSLog(#"Message failed");
}
There is no way to know the number to which user sent the message.
An Alternative would be like:
Implement ABPeoplePickerNavigationController for choosing a contact within your application. If they choose a contact present the MFMessageComposeViewController with your message and the number (chosen on the ABPeoplePickerNavigationController).
In that way you can keep track the number, there is no other way to do that.
In above case also after presenting the MFMessageComposeViewController, user can edit the number from there, you can't get the edited number then.
#MidhunMP answer is good, however there's one other way that you may implement.
Create a view which takes user name (if needed) and his phone number, and then on a button tap open MFMessageComposeViewController to send the message.
As I can see in your code, you should only give him a credit when message status is MessageComposeResultSent.
However, there's always chance of (as Midhun told), that user may change their number in MFMessageComposeViewController. The only way to overcome to this is to send SMS by your app only (doesn't matter via some SDKs or via APIs).

Not able to find players with GKMatchmakerViewController

I am trying to integrate Game Center for matching players. I am using that very simple function:
- (void)findOpponent {
GKMatchRequest* request = [[GKMatchRequest alloc] init];
request.minPlayers = 2;
request.maxPlayers = 2;
GKMatchmakerViewController *mmvc = [[GKMatchmakerViewController alloc]
initWithMatchRequest:request];
mmvc.matchmakerDelegate = self;
[[self viewController] presentViewController:mmvc animated:YES completion:nil];
}
I do have some callback, never called tho':
- (void)matchmakerViewController:(GKMatchmakerViewController *)viewController didFindMatch:(GKMatch *)theMatch {
NSLog(#"he");
[[self viewController] dismissViewControllerAnimated:NO completion:nil];
GKMatch* match = theMatch;
[match setDelegate:self];
NSLog(#"Ready to start match!");
}
- (void)matchmakerViewController:(GKMatchmakerViewController *)viewController didFindPlayers:(NSArray *)playerIDs {
NSLog(#"Super he");
}
- (void)matchmakerViewController:(GKMatchmakerViewController *)viewController didReceiveAcceptFromHostedPlayer:(NSString *)playerID {
NSLog(#"Wow");
}
When I test onmy device (wether iPhone or iPad), both using iOS 7.1, I can open Game Center from my Application, but as soon as I click on "Play Now" I instantaneously get the error: "Failed to find players". Yet none of my callback seems to get triggered in my code. Any idea of what I am doing wrong? I did try to reset my iPad settings, logging off from iCloud, rebooting my device, etc.
Fixed.
More than creating a Provisioning Profile and enabling Game Center inside, you also need to Add your app on iTunes Connect.
You need to go to an extremely strange process where it ask for the release date of your app, the price, some screen shots and icons, but once done you will be able to enable Game Center for real.

iOS 7: How to setup invitation handler for Game Center matchmaker

What is the proper way to handle invitations from other players in iOS 7?
After my view did load on my root View Controller, I'm calling a game center authentication method, after that I'm setup a invitation handler like so:
[[GKLocalPlayer localPlayer] registerListener:self];
My view controller adopt GKLocalPlayerListener and GKInviteEventListener protocols, by the way, what is the best place to register a listener AppDelegate? Maybe or maybe my custom Game Center singleton?
I add a method described in GKInviteEventListener
-(void)player:(GKPlayer *)player didAcceptInvite:(GKInvite *)invite
{
NSLog(#"Invite accepted!");
GKMatchmakerViewController *mmvc = [[GKMatchmakerViewController alloc] initWithInvite:invite];
mmvc.matchmakerDelegate = self;
[self presentViewController:mmvc animated:YES completion:nil];
}
But, game center matchmaker class have such topic: Receiving Invitations From Other Players and method – matchForInvite:completionHandler:
I don't understand how to use it.
So, what I must use and how?
I think you're doing things correctly. I did things the same way, and it works for me. -matchForInvite:completionHandler is deprecated in iOS 7, so I don't do anything with it.
First I set the authentication handler. This is called when my app loads for the first time, you can set it anywhere you like, but it is best to set the handler as soon as possible.
-(void)authenticateLocalPlayer
{
GKLocalPlayer *localPlayer = [GKLocalPlayer localPlayer];
__weak GKLocalPlayer *blockLocalPlayer = localPlayer;
//Block is called each time GameKit automatically authenticates
localPlayer.authenticateHandler = ^(UIViewController *viewController, NSError *error)
{
[self setLastError:error];
if (viewController)
{
self.authenticationViewController = viewController;
[self disableGameCenter];
}
else if (blockLocalPlayer.isAuthenticated)
{
[self authenticatedPlayer:blockLocalPlayer];
}
else
{
[self disableGameCenter];
}
};
}
If authentication is successful, then I call this method:
-(void)authenticatedPlayer:(GKLocalPlayer*)localPlayer
{
self.isAuthenticated = YES;
[[NSNotificationCenter defaultCenter]postNotificationName:AUTHENTICATED_NOTIFICATION object:nil];
[[GKLocalPlayer localPlayer]registerListener:self];
}
Then I implemented the two listener methods:
(void)player:(GKPlayer *)player didAcceptInvite:(GKInvite *)invite
{
//.... insert some cleanup code here to manage view controllers etc before presenting the matchmakerviewcontroller.
[self presentMatchmakerViewControllerWithInvite:invite];
}
-(void)player:(GKPlayer *)player didRequestMatchWithPlayers:(NSArray *)playerIDsToInvite
{
//......insert some cleanup code for managing view controllers
GKMatchRequest *match = [[GKMatchRequest alloc]init];
match.playersToInvite = playerIDsToInvite;
GKMatchmakerViewController *mmvc = [[GKMatchmakerViewController alloc]initWithMatchRequest:match];
mmvc.matchmakerDelegate = root.viewControllers[0];
[[[[[UIApplication sharedApplication]delegate]window]rootViewController]presentViewController:mmvc animated:YES completion:nil];
}

Receiving production ads and interstitials from AdMob in test mode

I'm testing AdMob ads in my iOS-application. AdMob seems to ignore the test-flag I put in the code:
-(IBAction)quitButtonHit:(id)sender{
[[AudioPlayer sharedManager] stopSound];
[self.timer invalidate];
interstitial_ = [[GADInterstitial alloc] init];
interstitial_.adUnitID = adMobUnitID;
interstitial_.delegate = self;
GADRequest *request = [GADRequest request];
request.testing = YES;
[interstitial_ loadRequest:[GADRequest request]];
}
-(void) interstitial:(GADInterstitial *)ad didFailToReceiveAdWithError:(GADRequestError *)error {
[self dismissViewControllerAnimated:YES completion:nil];
}
-(void) interstitialDidDismissScreen:(GADInterstitial *)ad {
[self dismissViewControllerAnimated:YES completion:nil];
}
-(void) interstitialDidReceiveAd:(GADInterstitial *)ad {
[ad presentFromRootViewController:self];
}
I am receiving production interstitials when I hit the Quit-button in my app. I do not understand why since Google states that they will invite you to be able to receive interstitials and because I set the test-flag on the request.
I am also receiving production ads in my app's AdMob banner. But that only goes for my device - on the simulators test ads are displayed. I also set the test-flag when requesting banners.
I would like the production ads to go away, so I won't have to worry about tapping them by accident.
I use AdMob's lates API (version 6.3.0). My deployment target is iOS 6.0.
Can anyone explain this and maybe suggest a solution to make the production ads go away?
Thanks!
Try this :
request.testDevices =
[NSArray arrayWithObjects:
// TODO: Add your device/simulator test identifiers here. They are
// printed to the console when the app is launched.
nil];

Resources