iOS Native Facebook Share no internet callback - iphone

I'm trying to implement the native facebook share for iOS 6 and need check if a share did succeed or not. This is the code I have used:
BOOL displayedNativeDialog =
[FBNativeDialogs
presentShareDialogModallyFrom:delegate
initialText:#"test"
image:nil
url:nil
handler:^(FBNativeDialogResult result, NSError *error) {
if (error) {
/* handle failure */
NSLog(#"error:%#, %#", error, [error localizedDescription]);
} else {
if (result == FBNativeDialogResultSucceeded) {
/* handle success */
NSLog(#"handle success");
} else {
/* handle user cancel */
NSLog(#"user cancel");
}
}
}];
if (!displayedNativeDialog) {
/* handle fallback to native dialog */
}
My problem is when I try this with no internet connection available I still get the FBNativeDialogResultSucceeded
It looks like you should get an error when no internet connection is available but it seems that it doesn't work like that.
If there are some solution where I don't need to use the reachability SDK that would be great.

You'll likely have to use the reachability SDK at this point. The Facebook SDK builds on top of the SLComposeViewController for the native functionality. That view controller returns two possible choices:
SLComposeViewControllerResultCancelled
SLComposeViewControllerResultDone
SLComposeViewControllerResultDone: The view controller is dismissed and the message is being sent in the background. This occurs when the user selects Done.
So since Facebook mirrors this the success case means the user clicked done and the message has been sent in the background.
However if you run this and there is no internet connection, the user should still see a pop-up indicating that the post could not be sent due to a connection failure.

Related

How to check if sim card is installed or not

I am developing an app which has call and message functionality , i want to check if sim card is installed or not coz i am facing problem with messaging as it gives alerts for " Message Sent Successful"
Please help me out.
There might be different ways but one way is by using MFMessageComposeViewController class to see if you can send the text message. If you can then sim is available otherwise not.
if ([MFMessageComposeViewController canSendText]) {
NSLog(#"SIM Available");
} else {
NSLog(#"no SIM card installed");
}
In cases you have iMessage available then this might return you true, you could also check if you can make a call, you might want to use CTTelephonyNetworkInfo for that purpose.
You can also check using like this.... First read this doc
http://developer.apple.com/library/ios/#DOCUMENTATION/NetworkingInternet/Reference/CTCarrier/Reference/Reference.html#//apple_ref/doc/uid/TP40009596-CH1-SW1
NSString *_code = [[[CTCarrier alloc] init] mobileCountryCode];
The value for this property is nil if any of the following apply:
The device is in Airplane mode.
There is no SIM card in the device.
The device is outside of cellular service range.
First you have to be sure that device is iPhone (not iPod or iPad) then check if device can make call or not, just like this............
if([[UIDevice currentDevice].model isEqualToString:#"iPhone"])
{
if ([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:#"tel:123456"]])
{
NSLog(#"Device can make call or send message");
}
else
{
NSLog(#"Device can not make call or send message");
}
}
else
{
NSLog(#"Device can not make call or send message");
}
Hope it will help you........

Allow Authenticated IOS Game Center Users to Auto-Authenticate

I am making an iphone app (a game) and while it will not be my first game, it will be my first game that uses a network connection (I intend on adding a few multiplier features)
So, now for my question.
I want the player to be able to open my app, sign into game center, and then use that to connect to my server. Is this possible? In other words:
Player signs in to game center
Sends username to my server
if (game center username doesnt exist)
{
Add their username to my sql database
}
else if (username does exist)
{
Send sign in successful message to device.
}
I believe I read another question from a while ago asking how to do this, but the answer said something about using the device UDID, which I do not want to do (for obvious reasons if you read technology related news).
So anyway, is there a trusted way that I can be sure that the user is who they say they are once they authenticate with game center that I can use to authenticate them against my server? Thank you
I think instead of UDID you can use GKPlayer.playerID which is unique to each gamecenter account. For your other purposes you can customize the completion block of authenticate handler
GKLocalPlayer * __weak localPlayer = [GKLocalPlayer localPlayer];
localPlayer.authenticateHandler = ^(UIViewController *viewController, NSError *error)
{
if (viewController != nil)
{
[currentViewController presentViewController:viewController animated:YES completion:nil];
}
else if (localPlayer.isAuthenticated)
{
NSLog(#"Player authenticated");
/* Your custom methods here
Sends username to my server -- send localPlayer.playerID to your server
if (game center username doesnt exist)
{
Add their username to my sql database
}
else if (username does exist)
{
Send sign in successful message to device.
}
*/
}
else
{
NSLog(#"Player not authenticated");
//disableGameCenter
}
NSLog(#"Error: %#",error);
};

How to tell when we are disconnected from GameCenter GKMatch session?

I'm wondering how do I get the disconnect message for local player when the game session is in progress and we're unable to communicate our data to other players. As there is nothing in documentation that says "this method will inform you whenever your connection fails", I'm at a bit of a loss.
I was trying to use this chunk of code in hopes that it would work, but it's futile. The "We're disconnected." message is never triggered.
- (void)match:(GKMatch *)theMatch player:(NSString *)playerID didChangeState:(GKPlayerConnectionState)state {
if (self.match != theMatch) return;
switch (state) {
case GKPlayerStateDisconnected:
//disconnected
NSLog(#"player status changed: disconnected");
matchStarted = NO;
GKLocalPlayer *player = [GKLocalPlayer localPlayer];
if ([playerID isEqualToString:player.playerID]) {
// We have been disconnected
NSLog(#"We're disconnected.");
}
if ([delegate respondsToSelector:#selector(matchEnded)]) {
[delegate matchEnded];
}
break;
}
}
The only other line that I found might tell us that we're unable to communicate is when we actually send data like this:
- (void)sendRandomMatchData:(NSData *)data {
GKMatch *match = [GCHelper sharedInstance].match;
BOOL success = [match sendDataToAllPlayers:data
withDataMode:GKMatchSendDataReliable
error:nil];
if (!success) {
[self matchEnded];
}
}
But I assume that "success" will also be false if the opponent has disconnected and we're unable to send messages to them.
I have a pretty strict game logics, if someone has been disconnected I need to inform them that they are unable to continue playing the match and that they have lost.
Any help is highly appreciated.
There are 2 places you can do this, both are in the GKMatchDelegate protocol.
The first is implementing:
- (void)match:(GKMatch *)match player:(NSString *)playerID
didChangeState:(GKPlayerConnectionState)state
{
}
And if it's a 2 player match, the second place you can catch the disconnect is:
- (BOOL)match:(GKMatch *)theMatch shouldReinvitePlayer:(NSString *)playerID
{
}
Both those events fire reliably when the GKMatch is terminated. If Stan's answer answered your question, then I would highly recommend getting in the practice of catching NSError wherever they are available! Can save you lots of time.
So to send data and catch the error:
NSError* nsErr ;
int result = [theMatch sendData:nsd toPlayers:theMatch.playerIDs
withDataMode:GKMatchSendDataReliable error:&nsErr] ;
if( !result ) { // NO if the match was unable to queue the data.
error( nsErr, "Failed to sendRoundtripPing" ) ;
}
What about examining the error after the following code line:
BOOL success = [match sendDataToAllPlayers:data
withDataMode:GKMatchSendDataReliable
error:nil]; //replace nil with NSError variable
Maybe error will give you extra info u need.
Another idea is to create NSTimer and set some certain time for making moves/turns. If some player didn't make it for a certain time then assume this player is disconnected. Also you could check your Internet connection state to determine you have a connection cuz maybe you just lost it and that's the reason you can't send/receive any data.
Also you could check every player periodically by sending them some short amount of data using GC just to make them answer you. This way you could ensure all players are "alive" or detect some "zombie".
Remember if player moves the game to background using Home button you won't detect it anyhow cuz code in your game wont execute. And this situation doesn't mean that player is "zombie". Player could be busy by a call or something else like another app. Player could temporary loose Internet connection. This means that he/she could return to game soon...

how do I connect to FB from WITHIN my ios app?

I have a popular medicine app often used by med students and residents at the bedside. I incorporated the new FB SKD into my last updated which, when opened for the first time (and subsequently if not used for a few days), opens the native FB app then redirects to my app. Many customers have complained because the info within the app often needs to be looked up quickly (crashing patient).
Is it possible to set up my app so the user needs to click on a button within the app before connecting to FB? Thanks!
I think you will need to make change to authorizeWithFBAppAuth method in facebook.m file of the SDK.
This SO has a suggestion for you.
When you download the FB SDK you get a sample project. Compile and run it, and you should see a toggle button that allows user to login/logout. You've got the FB official images in that project, and the code behind it is pretty simple:
/**
* Called on a login/logout button click.
*/
- (void)fbButtonClick:(id)sender {
if (fbButton.isLoggedIn) {
[self logout];
} else {
[self login];
}
}
/**
* Show the authorization dialog.
*/
- (void)login {
[_facebook authorize:nil delegate:self];
NSLog(#"Sas");
}
/**
* Invalidate the access token and clear the cookie.
*/
- (void)logout {
[_facebook logout:self];
}
You should also change the button's state in the FBAuth delegate methods (which you've already implemented) by calling a method similar to this one:
- (void)updateFbButtonAccordingToSessionStatus {
//Check if session is valid and update button accordingly
if ([self.facebook isSessionValid] == NO ) {
fbButton.isLoggedIn = NO;
[fbButton updateImage];
}
else {
fbButton.isLoggedIn = YES;
[fbButton updateImage];
}
}
Hope this helps.

Game Center- handling failed achievement submissions?

Im a noob in game center # games generally. Im making my second game now and implemented the game center.
If the internet is available, there is no problem, everything works well.
But just now I purposely make the internet unreachable, and when I get an achievement, obviously it does not register to the Game Center's Achievement.
How and what's the best way to handle this issue?
Thank you....
You could add the GKAchievement objects that fail to register to an array and then resend them when you get back connectivity. You should also consider committing that array to persistent storage, in case your app terminates before it has a chance to send those achievements. Try this in your completion handler:
// Load or create array of leftover achievements
if (achievementsToReport == nil) {
achievementsToReport = [[NSKeyedUnarchiver unarchiveObjectWithFile:pathForFile(kAchievementsToReportFilename)] retain];
if (achievementsToReport == nil) {
achievementsToReport = [[NSMutableArray array] retain];
}
}
#synchronized(achievementsToReport) {
if(error == nil)
{
// Achievement reporting succeded
// Resend any leftover achievements
BOOL leftoverAchievementReported = NO;
while ([achievementsToReport count] != 0) {
[self resendAchievement:[achievementsToReport lastObject]];
[achievementsToReport removeLastObject];
leftoverAchievementReported = YES;
}
// Commit leftover achievements to persistent storage
if (leftoverAchievementReported == YES) {
[NSKeyedArchiver archiveRootObject:achievementsToReport toFile:pathForFile(kAchievementsToReportFilename)];
}
}
else
{
// Achievement reporting failed
[achievementsToReport addObject:theAchievement];
[NSKeyedArchiver archiveRootObject:achievementsToReport toFile:pathForFile(kAchievementsToReportFilename)];
}
}
Hope this helps.
I see that the two answers here focus on the specific mechanisms for archiving the undelivered achievement messages. For a higher-level description of the overall approach, you can see my answer to this related question: Robust Game Center Achievement code
Achievements (and all of the gamecenter stuff like leaderboard updates) conform to NSCoding. You can store them if you get an error submitting them and submit them later. This is what apple recommends in their docs.
Your application must handle errors when it fails to report progress to Game Center. For example, the device may not have had a network when you attempted to report the progress. The proper way for your application to handle network errors is to retain the achievement object (possibly adding it to an array). Then, your application needs to periodically attempt to report the progress until it is successfully reported. The GKAchievement class supports the NSCoding protocol to allow your application to archive an achievement object when it moves into the background.
from: http://developer.apple.com/library/ios/#documentation/NetworkingInternet/Conceptual/GameKit_Guide/Achievements/Achievements.html#//apple_ref/doc/uid/TP40008304-CH7-SW13
// Submit an achievement to the server and store if submission fails
- (void)submitAchievement:(GKAchievement *)achievement
{
if (achievement)
{
// Submit the achievement.
[achievement reportAchievementWithCompletionHandler: ^(NSError *error)
{
if (error)
{
// Store achievement to be submitted at a later time.
[self storeAchievement:achievement];
}
else
{
NSLog(#"Achievement %# Submitted..",achievement);
if ([storedAchievements objectForKey:achievement.identifier]) {
// Achievement is reported, remove from store.
[storedAchievements removeObjectForKey:achievement.identifier];
}
[self resubmitStoredAchievements];
}
}];
}
}
In case anyone stumbles upon this question in the future, Apple now has sample code for submitting achievements that includes a way to archive achievements that failed to submit (due to no network connection, etc). You'll find it in the Game Center programming guide.