GameKit programmatic matching flow - ios

I'm having the devils own time with Game Kit programmatic matching, and can only assume that despite reading all the tutorials I can lay my hands on... I've got the flow wrong somewhere.
Sign in to the Sandbox works fine, the app is being distributed with an App ID specific profile that is Game Center enabled. It all seems to work fine except that it never finds another "nearby" player.
The code below is my authentication handler, which is called correctly, but as I say despite it logging "Starting browser for nearby players", none are ever reported, blue tooth on same wifi network etc etc etc. Utterly perplexed as to what I am doing wrong.
-(void) authenticationHandler{
if ([_currentScene conformsToProtocol:#protocol(BOMScene)]){
MyScene<BOMScene> *theScene = (MyScene<BOMScene> *) _currentScene;
//Make sure the current scene gets the message that they are now authenticated
if ([GKLocalPlayer localPlayer].isAuthenticated){
[theScene localPlayerAuthenticated];
} else {
[theScene localPlayerDeauthenticated];
}
}
NSLog(#"Game Center Status Change: %#", _localPlayer.authenticated ? #"Available" : #"Not Available");
if (_localPlayer.authenticated){
if (!_matchMaker){
_matchMaker= [GKMatchmaker sharedMatchmaker];
NSLog(#"Starting to browser for nearby players");
[_matchMaker startBrowsingForNearbyPlayersWithReachableHandler:^(NSString *playerID, BOOL reachable) {
NSLog(#"Nearby player %# is %#",playerID, reachable ? #"available" : #"no longer available");
if (reachable){
[_nearbyPlayers addObject:playerID];
} else {
[_nearbyPlayers removeObject:playerID];
}
}];
}
} else {
_matchRequest = nil;
[_matchMaker stopBrowsingForNearbyPlayers];
[_nearbyPlayers removeAllObjects];
_matchMaker = nil;
}

You need to install an invitation handler.
Please see my answer here for a full breakdown:
Some startBrowsingForNearbyPlayersWithReachableHandler questions

Related

High number of users fail to purchase my IAP. Is this to be expected?

After adding analytics to my app, I have seen a very high number of users reach an error when trying to purchase a product within my app. Not all fail though.
.03% of all my users reach the error
.002% of my users successfully purchase the product
It's been very hard for me to debug because when I test with different devices and different apple accounts, the purchase always succeeds.
The error event is called when either 0 SKProducts can be found (they must have no internet?), or when they attempt to purchase, the transaction reads SKPaymentTransactionStateFailed.
My question is, how should I go about debugging this? What is the normal percentage of users that fail to purchase a product (maybe their iCloud isn't setup correctly, or their payment is declined). I still get a relatively normal amount of revenue from the IAP, so clearly it is working for some people. Am I really missing out on all these purchases due to a bug, or is something else going on?
My purchase code looks like this. I am using a pod called IAPHelper. I am highly doubtful the pod is the problem, since I've switched it out and had the same results.
- (void)makePurchase {
SKProduct* product =[[IAPShare sharedHelper].iap.products objectAtIndex:0];
[[IAPShare sharedHelper].iap buyProduct:product
onCompletion:^(SKPaymentTransaction* trans){
if(trans.error){
[self showErrorPurchasing:trans.error];
} else if(trans.transactionState == SKPaymentTransactionStatePurchased) {
[[IAPShare sharedHelper].iap provideContentWithTransaction:trans];
[self purchaseSucceeded];
} else if(trans.transactionState == SKPaymentTransactionStateFailed) {
[self showErrorPurchasing:trans.error];
} else if(trans.transactionState == SKPaymentTransactionStateDeferred) {
[self hideHud];
} else if(trans.transactionState == SKPaymentTransactionStateRestored) {
[self purchaseSucceeded];
}
}];
}
Thank you
I can't answer your question directly but in terms of the code maybe this will help. When you do
SKProduct* product =[[IAPShare sharedHelper].iap.products objectAtIndex:0];
the objectAtIndex will crash if the array is empty. Either test the array to make sure it has products or use firstObject and then test if firstObject is nil. So in summary
SKProduct * product = [... firstObject];
if ( product )
{
... your code ...
}
else
{
... unable to read products / no connection ...
}
Your users might have cancelled the purchase without continuing. In that case, you will receive purchase failed state.
Check whether the error code 2, to identify a user purchase cancel event. Here's how I handle it in my swift project. Hope this helps.
case .failed:
let errorCode = (trans.error as? SKError)?.code
if (errorCode == .paymentCancelled) {
//Handle cancelled purchase
}

removeTracksFromPlaylist not removing tracks with ios spotify sdk

I was testing this method to remove tracks from a playlist. Basically I modified the demo project "simple track playback" provided with the SDK. I wanted to remove the track form the playlist when you hit fastForward. I changed the fastForward method this way but it's not doing anything, and error is nil.
-(IBAction)fastForward:(id)sender {
if([self.player isPlaying] && self.currentPlaylistSnapshot){
SPTAuth *auth = [SPTAuth defaultInstance];
[self.currentPlaylistSnapshot removeTracksFromPlaylist:#[self.player.currentTrackURI]
withAccessToken:auth.session.accessToken
callback:^(NSError *error) {
if (error != nil) {
NSLog(#"*** Failed to remove track : %#", self.titleLabel.text);
return;
}
}];
}
[self.player skipNext:nil];
}
self.currentPlaylistSnapshot is the one I've got from the handleNewSession method.
There's also a static method apparently offering something similar which I have't tried yet.
createRequestForRemovingTracks:fromPlaylist:withAccessToken:snapshot:error:
According to the documentation both options are implemented asynchronously and will take seconds to reflect the results in the server but I'm suspecting that there's either something wrong or I'm just missing to do an actual request to push the changes on the local snapshot maybe?
Documentation:
https://developer.spotify.com/ios-sdk-docs/Documents/Classes/SPTPlaylistSnapshot.html#//api/name/removeTracksWithPositionsFromPlaylist:withAccessToken:callback:
ios sdk:
https://github.com/spotify/ios-sdk
I solved my issue by reseting simulator + adding SPTAuthPlaylistModifyPublicScope (which I fogot to do...)
auth.requestedScopes = #[SPTAuthStreamingScope, SPTAuthPlaylistModifyPublicScope];

How to check if vungle video is complete or user close the vungle video?

I am working on vungle video integration in cocos 2d and and running the ad successfully.
In app i want to provide some points for watching video.. which i can set up.. but the problem is how to check whether the user has watched the video or close it ..
https://v.vungle.com/dev/ios
I am using the above help.. but not able to make it work..Please help me in checking whether app is ads are close or watched completely
- (void)vungleSDKwillCloseAdWithViewInfo:(NSDictionary *)viewInfo willPresentProductSheet:(BOOL)willPresentProductSheet {
//Verify that the view was completed before rewarding the user
BOOL completedView = [[viewInfo valueForKey:#"completedView"] boolValue];
if (completedView) {
//View was successfully completed, do your stuff...
}
}
Few months back I did use vungle. Check below code, that worked for me
-(void)vungleMoviePlayed:(VGPlayData*)playData
{
if(playData.movieTotal == playData.movieViewed)
{
printf("Video fully watched\n");
mSeenVungleVideo = true;
}
else
{
printf("Player aborted video at middle\n");
}
}
This seems to have changed since NatureFriend's answer. It's now:
- (void)vungleSDKwillCloseAdWithViewInfo:(NSDictionary*)viewInfo willPresentProductSheet:(BOOL)willPresentProductSheet;
{
// video done here.
}
It's possible at this point it will show a "Product Sheet". If you want to know when that closes, you can implement this delegate:
- (void)vungleSDKwillCloseProductSheet:(id)productSheet
{
// product sheet closed here
}

Intercepting phone call - iPhone (correct method to hook in CoreTelephony)

I am new to the jailbreak tweak development scene. I am trying to figure out the appropriate method to 'hook' so I can intercept an incoming call (and then run some code).
I have dumped the header files of CoreTelephony framework however no methods seem obvious to hook. I have tried:
- (void)broadcastCallStateChangesIfNeededWithFailureLogMessage:(id)arg1;
- (BOOL)setUpServerConnection;
but neither have worked. By worked I mean - get called when the iPhone receives a call.
Any pointers as to the appropriate method to hook? Thanks :)
Note:
This is going to be a jailbreak tweak using private APIs so it won't be submitted to the App Store.
I didn't test your code, but I think your problem might be that you need to use the Core Telephony notification center to register for that event (not what you had in the code in your comment). Something like this:
// register for all Core Telephony notifications
id ct = CTTelephonyCenterGetDefault();
CTTelephonyCenterAddObserver(ct, // center
NULL, // observer
telephonyEventCallback, // callback
NULL, // event name (or all)
NULL, // object
CFNotificationSuspensionBehaviorDeliverImmediately);
and your callback function is
static void telephonyEventCallback(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo)
{
NSString *notifyname = (NSString*)name;
if ([notifyname isEqualToString:#"kCTCallIdentificationChangeNotification"])
{
NSDictionary* info = (NSDictionary*)userInfo;
CTCall* call = (CTCall*)[info objectForKey:#"kCTCall"];
NSString* caller = CTCallCopyAddress(NULL, call);
if (call.callState == CTCallStateDisconnected)
{
NSLog(#"Call has been disconnected");
}
else if (call.callState == CTCallStateConnected)
{
NSLog(#"Call has just been connected");
}
else if (call.callState == CTCallStateIncoming)
{
NSLog(#"Call is incoming");
}
else if (call.callState == CTCallStateDialing)
{
NSLog(#"Call is Dialing");
}
else
{
NSLog(#"None of the conditions");
}
}
}
I offer another technique in this similar question here. Also, note my comment in that question about not getting the notifications in a UIApplication that has been put into the background.
Update: see cud_programmer's comment below about using kCTCallStatus on iOS 6 instead of kCTCall.
Is it possible?
Yes.
Would a regular average person with no background in computer engineering or knowhow of how cell towers work be capable of something like this?
No.
Technically you can buy router looking thing to do this which aren’t cheap, are illegal and cellphone companies can actually track them down since it interferes with the network. So other than government agencies or international spies i don’t think you have anything to worry about. But if the government is exactly what you’re worried about well I’m sorry to tell you they’ve been doing a lot more then intercepting just phones

GKTurnBasedMatch quitting out of turn

When a user quits "in turn" in a turn based match in an iOS app using GameKit, the delegate method -(void)turnBasedMatchmakerViewController: (GKTurnBasedMatchmakerViewController *)viewController playerQuitForMatch:(GKTurnBasedMatch *)match; is called on the GKTurnBasedMatchmakerViewController, in which according to the documentation, we should set the outcome for current player, and call participantQuitInTurnWithOutcome:nextParticipant:matchData:completionHandler:
However, I am not able to find any information regarding a player quiting out of turn. That is when it isn't my turn and I quit from the matchmaker viewcontroller. There doesn't seem to be any delegate method for that, and surprisingly, from debugging my app, I find out that turn is sent (even though it isn't my turn currently in the match).
Can anyone please explain the behavior and the correct way to handle out of turn quits.
You can handle this scenario in
-(void)handleTurnEventForMatch:(GKTurnBasedMatch *)match
Loop through the participants and if the triggering player is the local player, and his outcome is "Quit", and he's not the current participant (which is handled in another place -turnBasedMatchmakerViewController:playerQuitForMatch:), then go ahead and quit the game out of turn.
for (int i = 0; i < [match.participants count]; i++)
{
GKTurnBasedParticipant *p = [match.participants objectAtIndex:i];
if ([p.playerID isEqualToString:[GKLocalPlayer localPlayer].playerID])
{
// Found player
if (p.matchOutcome == GKTurnBasedMatchOutcomeQuit)
{
// Player Quit... ignore current participants and end out of turn only for the other player
if (![match.currentParticipant.playerID isEqualToString:p.playerID])
{
// not the current participant and he quit
[match participantQuitOutOfTurnWithOutcome:GKTurnBasedMatchOutcomeQuit withCompletionHandler:nil];
break;
}
}
}
}
You can check which is the current participant from the match and see if that is you. As for the sent traffic, doesn't Game Center need to inform all other players that you have quit?
There is actually a method to quit out of turn:
For a GKTurnBasedMatch it's called:
participantQuitOutOfTurnWithOutcome:withCompletionHandler:
You can call it in your GKTurnBaseMatchMakerViewControllerDelegate, when the turnBasedMatchmakerViewController:playerQuitForMatch: function is called.
Please see the official doc here

Resources