Related
I'm trying to Fetch User's friends List.
my last working Code that i implement in FacebookSDK 3.12 is now of No use because facebook have changed all their classes and even deleted old Classes, below is my old Code:
#pragma mark - Facebook Methods -
-(void)initiateFacebookSessionIfNot
{
if (FBSession.activeSession.isOpen)
{
[self getUserFriendsIds];
} else
{
NSArray *permissions = [[NSArray alloc] initWithObjects:
#"user_birthday",#"friends_hometown",
#"friends_birthday",#"friends_location",
nil];
[FBSession openActiveSessionWithReadPermissions:permissions allowLoginUI:YES completionHandler:^(FBSession *session, FBSessionState status,NSError *error)
{
if (error) {
NSString *alertMessage, *alertTitle;
if (error.fberrorShouldNotifyUser) {
alertTitle = #"Something Went Wrong";
alertMessage = error.fberrorUserMessage;
} else if (error.fberrorCategory == FBErrorCategoryUserCancelled) {
NSLog(#"user cancelled login");
} else {
// For simplicity, this sample treats other errors blindly.
alertTitle = #"Unknown Error";
alertMessage = #"Error. Please try again later.";
NSLog(#"Unexpected error:%#", error);
}
if (alertMessage)
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:alertTitle
message:error.fberrorUserMessage
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
}
} else if (FB_ISSESSIONOPENWITHSTATE(status)) {
[self getUserFriendsIds];
}
}];
}
}
-(void)getUserFriendsIds
{
FBRequest *friendRequest = [FBRequest requestForGraphPath:#"me/friends?fields=name,username"];
[ friendRequest startWithCompletionHandler:^(FBRequestConnection *connection, id result, NSError *error) {
NSMutableArray *fbFriendIDs;
NSMutableArray *fbFriendsName;
NSMutableArray *fbFriendsUserName;
NSMutableArray *data = [[NSMutableArray alloc]initWithArray:[result objectForKey:#"data"]];
[data enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
if (!(NSDictionary*)obj[#"username"]) {
NSDictionary *newDictionary =#{#"id": (NSDictionary*)obj[#"id"],
#"name": (NSDictionary*)obj[#"name"],
#"username": #"0"
};
[data replaceObjectAtIndex:idx withObject:newDictionary];
}
}];
fbFriendsUserName = [[NSMutableArray alloc]initWithArray:[data valueForKeyPath:#"#unionOfObjects.username"]];
fbFriendsName = [[NSMutableArray alloc]initWithArray:[data valueForKeyPath:#"#unionOfObjects.name"]];
fbFriendIDs = [[NSMutableArray alloc]initWithArray:[data valueForKeyPath:#"#unionOfObjects.id"]];
NSDictionary *queryDictionary =
#{#"user_id": userObj.user_id,
#"friend_ids":[fbFriendIDs componentsJoinedByString:#","],
#"names":[fbFriendsName componentsJoinedByString:#","],
#"usernames":[fbFriendsUserName componentsJoinedByString:#","]
};
[[RequestHandler sharedClient] CheckFBFriendsWithDictionary:queryDictionary WithCompletionBlock:^(NSArray *TUNFriendsArray, NSArray *FBFriendsArray, NSString *errorMessage) {
if (!errorMessage) {
tunFriendsArray = [[NSMutableArray alloc]initWithArray:TUNFriendsArray];
// fbFriendsArray = [[NSMutableArray alloc]initWithArray:FBFriendsArray];
[_facebookTableView reloadData];
}
else{
[ApplicationUtilities ShowAlertViewWithTitle:APP_NAME Message:errorMessage];
}
}];
}];
[SVProgressHUD dismiss];
}
Facebook has changed a lot of implementation in their new version i.e. V2.0 in which Tag-gable Friends API, Invitable Friend API,Social Context API,Business Mapping API and Tagged Places API are the new features.
They have also made many permission changes so as to increase security read more on this from the following link
https://developers.facebook.com/docs/apps/changelog#v2_0_permissions
Hope you will find your required implementation changes from the above links.
It's no longer possible to receive the username field, as well as every information of the user's friends other than the public_profile, because all the friends_* permissions have been removed since v2.0.
Furthermore, you don't receive the full friends list, but only those which also use your app.
See
https://developers.facebook.com/docs/apps/changelog#v2_0_graph_api
https://developers.facebook.com/docs/apps/changelog#v2_0_permissions
Quotes:
/me/username is no longer available.
The /me/friends endpoint no longer includes the full list of a person's friends. Instead, it now returns the list of that person's friends who are also using your app.
All friends_* permissions have been removed.
My question is predicated on Jason Clark’s statement at f8 2014 that app links is designed to sit side by side well with deep linking technologies. I have a word game app published in 2013 to Canada and Australia using Facebook’s authentication but without deep linking. For the US market launch my intent was to add Facebook deep linking. Managed with the request and feed dialogs to send the Match Identifier UUID for both initiating a match and then bragging about the match (FriendSmash example) at that time to open the game on that match. My day job got in the way and I did not have time to finish QA and support a launch to the US. Last summer I upgraded SDKs (Facebook 3.14) and the url query no longer contained the string ‘notif’ to allow me to parse for the match Id. Therefore, I switched from using [FBSession.activeSession handleOpenURL:url] to the current [FBAppCall handleOpenURL:url …] and some other code from the new FriendSmash example. However, the url passed from the Facebook app no longer contains the ‘ref’ and therefore not the ‘notif’ which was the method documented to utilize my deep linking content. I have since updated my project to Facebook iOS SDK 3.21 (predicated in part by other SDKs, e.g. AWS not supporting arm64).
I currently use the following code to send the brag
- (void) sendBrag
{
// This function will invoke the Feed Dialog to post to a user's Timeline and News Feed
// It will attemnt to use the Facebook Native Share dialog
// If that's not supported we'll fall back to the web based dialog.
NSArray *friend = [[NSArray alloc] initWithObjects: bragMatch.opponentFacebookId, nil];
NSString *linkURL = [NSString stringWithFormat:#"http://www.ruleofwords.com/?deeplink_matchno=%#", bragMatch.initiatorMatchNo];
//NSString *linkURL = [NSString stringWithFormat:#"http://www.ruleofwords.com"];
NSString *pictureURL = #"https://pacific-castle-1361.herokuapp.com/rowappicon.png";
NSMutableString *msg = [[NSMutableString alloc]
initWithString:#"Just scored 0 points in Rule of Words. Good luck trying to beat that."];
[msg replaceOccurrencesOfString:#"0" withString:bragMatch.initiatorMatchPoints
options:NSBackwardsSearch range: NSMakeRange(0, [msg length])];
// Prepare the native share dialog parameters
FBLinkShareParams *shareParams = [[FBLinkShareParams alloc] init];
shareParams.friends = friend;
shareParams.link = [NSURL URLWithString:linkURL];
shareParams.name = #"Rule of Words Bragging Rights";
shareParams.caption= msg;
shareParams.picture= [NSURL URLWithString:pictureURL];
shareParams.linkDescription = #"Rule of Words, the contagious photography word social game on iPhone.";
if ([FBDialogs canPresentShareDialogWithParams:shareParams]){
[FBDialogs presentShareDialogWithParams:shareParams
clientState:nil
handler:^(FBAppCall *call, NSDictionary *results, NSError *error) {
if(error) {
NSLog(#"Error publishing story.");
} else if (results[#"completionGesture"] && [results[#"completionGesture"] isEqualToString:#"cancel"]) {
NSLog(#"User canceled story publishing.");
} else {
NSLog(#"Story published.");
}
}];
} else {
// Prepare the web dialog parameters
NSDictionary *params = #{
#"to": bragMatch.opponentFacebookId,
#"name" : shareParams.name,
#"caption" : shareParams.caption,
#"description" : shareParams.linkDescription,
#"picture" : pictureURL,
#"link" : linkURL
};
// Invoke the dialog
[FBWebDialogs presentFeedDialogModallyWithSession:nil
parameters:params
handler:
^(FBWebDialogResult result, NSURL *resultURL, NSError *error) {
if (error) {
NSLog(#"Error publishing story %#.", error);
} else {
if (result == FBWebDialogResultDialogNotCompleted) {
NSLog(#"User canceled story publishing.");
} else {
NSLog(#"Story published.");
}
}}];
}
}
(Aside - In my stepping through the sendBrag code the FBDialogs canPresentShareDialogWithParams always fails so that every time it defaults to a feed dialog. Anyone know what is the state is where the share dialog works? )
Then in my AppDelegate I have…
- (BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
sourceApplication:(NSString *)sourceApplication
annotation:(id)annotation {
NSLog(#"app is %# and url is %# and sourceApp is %#", application, url, sourceApplication);
// attempt to extract a token from the url
return [FBAppCall handleOpenURL:url
sourceApplication:sourceApplication
fallbackHandler:^(FBAppCall *call) {
// If there is an active session
if (FBSession.activeSession.isOpen) {
// Check the incoming link
[self handleAppLinkData:call.appLinkData];
} else {
NSLog(#"Access Token is %#", call.accessTokenData);
if (call.accessTokenData) {
// If token data is passed in and there's
// no active session.
if ([self handleAppLinkToken:call.accessTokenData]) {
// Attempt to open the session using the
// cached token and if successful then
// check the incoming link
[self handleAppLinkData:call.appLinkData];
}
}
}
}];
- (void) handleAppLinkData:(FBAppLinkData *)appLinkData {
NSURL *targetURL = appLinkData.targetURL;
if (targetURL) {
//NSURL *targetURL = [NSURL URLWithString:targetURLString];
NSDictionary *targetParams = [self parseURLParams:[targetURL query]];
NSString *ref = [targetParams valueForKey:#"ref"];
// Check if ref parm is among incoming news feed link, otw attribution link
if ([ref isEqualToString:#"notif"]) {
// Get the request id
NSString *requestIDParam = targetParams[#"request_ids"];
NSArray *requestIDs = [requestIDParam
componentsSeparatedByString:#","];
// Get data (of last request) from Graph API call to request id endpoint
//
[self notificationGet:requestIDs[[requestIDs count]-1]];
}
}
}
- (void) notificationGet:(NSString *)requestid {
__block NSString *title;
__block NSString *message;
[FBRequestConnection startWithGraphPath:requestid
completionHandler:^(FBRequestConnection *connection,
id result,
NSError *error) {
if (! error) {
if (result[#"data"])
{
title = [NSString stringWithFormat:
#"%# requests a match!", result[#"from"][#"name"]];
NSString *jsonString = result[#"data"];
NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
if (!jsonData) {
NSLog(#"JSON decode error: %#", error);
return;
}
NSError *jsonError = nil;
NSDictionary *requestData =[NSJSONSerialization JSONObjectWithData:jsonData options:0
error:&jsonError];
if (jsonError) {
NSLog(#"JSON decode error: %#", error);
return;
}
message = [NSString stringWithFormat:#"Match #: %#, Flashes: %#",
requestData[#"deeplink_matchno"],
requestData[#"flashes_gifted"]];
// set global opponentFacebookId for bragging
[[rowGlobals sharedGlobalVars] setRowGlobal:requestData[#"deeplink_matchno"]
forKey:#"deeplink_matchno"] ;
// Set up FB Deep Link Notification
// homeViewController is registered for notification
[[NSNotificationCenter defaultCenter]
postNotificationName:FBDeepLinkNotification
object:requestData[#"deeplink_matchno"]];
NSLog(#"successfully posted DeepLink notification") ;
} else {
title = [NSString stringWithFormat:#"%# sent you a request", result[#"from"][#"name"]];
message = result[#"message"];
}
// Delete the request notification
[self notificationClear:result[#"id"]];
} else {
title = #"General Deep Link Error" ;
message = #"Error occured with Facebook FBRequest Connection. This Facebook notification likely has been previously processed." ;
}
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:title
message:message
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil,
nil];
[alert show];
}];
}
Now I recognize I have some clean up to align the dialog setup with how I parse appLinkData to get the matchId UUID for my NSNotification to open on the game, but I am not getting that far to bother cleaning it up.
I have tried many meta tags on my site but at the moment I am just using
<meta property=”al:ios:url” content=”ruleofwords”>
where ruleofwords is a custom URL I added to my app’s plist.
but I cannot seem to put together any URL other than
NSString *linkURL = [NSString stringWithFormat:#"http://www.ruleofwords.com"];
which will launch my game by clicking on the Facebook link…
When I use anything like
NSString *urlLink = [NSString stringWithFormat:#"https://www.ruleofwords.com/?deeplink_matchNo=%#", bragMatch.initiatorMatchNo];
Then Facebook will only launch my web page without the custom URL link to my game.
Moreover, Facebook no longer launches it directly; it brings up my web page with an added link displayed as the offset brackets app Links logo.(Although not explicit it does technically follow the Facebook flow diagram). Touching this app Link logo does launch my game. This seems to be the case whether I have the meta tag on my website or not (now I may have other problems since we are only using Godaddy website builder).
Previously with the request dialog I had the ability to populate values such as #”data” with things like my match Id and gifts
NSData *jsonData = [NSJSONSerialization
dataWithJSONObject:#{
#"deeplink_matchno": bragMatch.initiatorMatchNo,
#"flashes_gifted": #"0"}
options:0
error:&error];
if (!jsonData) {
NSLog(#"JSON error: %#", error);
return;
}
NSString *challengeStr = [[NSString alloc]
initWithData:jsonData
encoding:NSUTF8StringEncoding];
NSMutableDictionary *params =
[NSMutableDictionary dictionaryWithObjectsAndKeys:
bragMatch.opponentFacebookId, #"to",
#"Rule of Words Bragging", #"name",
msg, #"caption",
#"Rule of Words, the contagious photography word social game on iPhone.",
#"description",
urlLink, #"link",
#"https://pacific-castle-6969.herokuapp.com/rowappicon.png", #"picture",
challengeStr, #"data",
nil];
// Invoke the dialog
//[self.facebook dialog:#"feed" andParams:params andDelegate:self];
//[FBWebDialogs presentFeedDialogModallyWithSession:nil
[FBWebDialogs presentRequestsDialogModallyWithSession:nil
message:msg
title:nil
parameters:params
handler:
^(FBWebDialogResult result, NSURL *resultURL, NSError *error) {
if (error) {
// Case A: Error launching the dialog or publishing story.
NSString *errormsg = [NSString stringWithFormat:#"Error encountered posting Facebook brag with error %#", error.localizedDescription];
NSLog(#"%#", errormsg);
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle:#"Facebook Brag Error"
message:errormsg
delegate:nil
cancelButtonTitle:#"Ok"
otherButtonTitles: nil];
[alert show];
} else {
if (result == FBWebDialogResultDialogNotCompleted) {
// Case B: User clicked the "x" icon
NSLog(#"Player canceled Facebook brag post via x icon.");
} else {
// Case C: Dialog shown and the user clicks Cancel or Share
NSDictionary *urlParams = [self parseURLParams:[resultURL query]];
//if (![urlParams valueForKey:#"post_id"]) {
if ([urlParams valueForKey:#"error_code"]) {
// User clicked the Cancel button
NSLog(#"error message is %#", [urlParams valueForKey:#"error_message"]);
NSLog(#"Player canceled Facebook brag post via Cancel button.");
} else {
// User clicked the Share button
//NSString *postID = [urlParams valueForKey:#"post_id"];
NSString *postID = [urlParams valueForKey:#"request"];
NSLog(#"Player Successfuly Posted RoW Match via Facebook brag, id: %#", postID);
}
}
}
}];
However, I no longer have al_applink_data in the passed URL for this request dialog, it just has an access_token with the original custom URL.
url is fb407545862655947://authorize/#access_token=CAAFyqSpfj8sBAGxahmdTCl1D9fs5hZBt3OfKP2MHCtM8STHadqEjlyFnXDTNHScjsxZCI6q0H8ZAppNSqJIJt83uN4LemkfklLjOdPTv3JZBtg3xTVZBKOhzdOMaZCGob5x2FPddZBzmaZBhIaE8dIgNqPfi9IlEuwQ2oHq6tEgA1w1pNESnHuDyK9gD7vswAC93nO7cCmCT4KBgxI22UDB3nINYZA058g8AZD&expires_in=3600 and sourceApp is com.facebook.Facebook
When I add the #”data” param with
[FBWebDialogs presentFeedDialogModallyWithSession:…]
although this argument is accepted by the feed dialog I the url does not get my match UUID or anything extra from my #”data” param…
url is ruleofwords:///?al_applink_data=%7B%22target_url%22%3A%22http%3A%5C%2F%5C%2Fwww.ruleofwords.com%5C%2F%22%2C%22extras%22%3A%7B%22fb_ref%22%3A%22Default%22%7D%2C%22referer_app_link%22%3A%7B%22url%22%3A%22fb%3A%5C%2F%5C%2F%5C%2F%3Fbacktrack_id%3Ddlr5p6iu_6a-OeUn%22%2C%22app_name%22%3A%22Facebook%22%7D%7D and sourceApp is com.facebook.Facebook
So I am at a loss how I am supposed to inject content specific information so that I can open my game with the match, which the opponent has requested or bragged about. I probably would have given up a long time ago but I did once have deep linking working (SDK 3.5?). I am wondering if I should be at another release level of the SDK for deep linking. It seems like the Facebook platform has significantly changed how it packages appLinkData. And although Facebook’s documentation has improved over the past two years, many of the examples which are required to put this all together do not seem to be referring to the same level of SDK. So Facebook how do I inject content into appLinkData so I can support deep linking with SDK 3.21? I thought about adding the Bolts framework but Jason implied it was designed for outlinking apps, which is not my case.
I can directly type in my iPhone Safari something like ‘ruleofwords://matchId=UUID’ and get the app delegate to parse out the [url query] so I could probably implement deep linking with push notifications, but I still like the ability to have a Facebook user tap on a link and launch the specific match directly.
Please see the 29th December update notes at the bottom of the page.
Hi I'm doing maintanance work on someone else's iOS project at work (which is kind of soul destroying because they haven't documented their code).
The problem is that after the user logs in, attempting to share a post to the wall always results in
error 100: "The post's links must direct to the application's connect or canvas URL".
I've searched for the past 2 hours and haven't found any results specifically for iOS (but plenty for wordpress, which didn't help)
Any ideas what might be causing this.
Here's the overseas developer code for posting to the wall:
-(void)uploadPropertyDetailsOnFacebookWall
{
[FBSettings setLoggingBehavior:[NSSet setWithObjects:FBLoggingBehaviorFBRequests, FBLoggingBehaviorFBURLConnections, nil]];
NSString* photoURL = #"";
NSString *strFullPropertyDetailLink=#"";
if (!kIsListOnce) {
photoURL = [currentItem objectForKey:#"Photo1FeaturedURL"];
strFullPropertyDetailLink=[currentItem objectForKey:#"FullDisplayLink"];
}
else {
strFullPropertyDetailLink=[currentItem objectForKey:#"FullDisplayLink"];
NSArray* list = [[currentItem objectForKey:#"objects"] objectForKey:#"img_small"];
;
if ([list count] > 0) {
photoURL = [list objectAtIndex:0];
}
}
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
NSString *strLinkOfApp=(NSString *)[Utils config:KiTunesstoreAppLink]; //strFullPropertyDetailLink,
NSDictionary *postParams =
[[NSMutableDictionary alloc] initWithObjectsAndKeys:
strFullPropertyDetailLink, #"link",
photoURL, #"picture",
[Utils config:kTextAgentName], #"name",
strAddress, #"caption",
[currentItem objectForKey:#"Description"], #"description",
nil];
[FBRequestConnection startWithGraphPath:#"me/feed"
parameters:postParams
HTTPMethod:#"POST"
completionHandler:^(FBRequestConnection *connection,
id result,
NSError *error)
{
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
NSString *alertText;
NSLog(#"%#",error);
if (error) {
NSDictionary *dict=[error userInfo];
NSLog(#"%#",dict);
NSDictionary *dictJSON=[dict objectForKey:#"com.facebook.sdk:ParsedJSONResponseKey"];
NSDictionary *dictBody=[dictJSON objectForKey:#"body"];
NSDictionary *dictError=[dictBody objectForKey:#"error"];
NSString *strCode=[[dictError objectForKey:#"code"] description];
if([strCode isEqualToString:#"200"])
{
alertText = #"You have not authorized the application to perform this publish action";
}else{
alertText = [#"An error ocurred: " stringByAppendingString:error.description];
alertText=[alertText stringByAppendingString: strFullPropertyDetailLink];
}
} else {
alertText = [NSString stringWithFormat:
#"Property details has been successfully shared on your Facebook Wall"];
}
[[[UIAlertView alloc] initWithTitle:#"Result"
message:alertText
delegate:nil
cancelButtonTitle:#"OK!"
otherButtonTitles:nil] show];
// Show the result in an alert
}];
}
Here's the error I keep getting:
Error Domain=com.facebook.sdk Code=5 "The operation couldn’t be completed(com.facebook.sdk error 5.)" UserInfo=0x1d548710 {com.facebook.sdk:ParsedJSONResponseKey={
body = {
error = {
code = 100;
message = "(#100) The post's links must direct to the application's connect or canvas URL.";
type = OAuthException;
};
};
code = 400;
}, com.facebook.sdk:HTTPStatusCode=400}
2013-08-02 12:06:12.806 RealEstate[385:907] {
"com.facebook.sdk:HTTPStatusCode" = 400;
"com.facebook.sdk:ParsedJSONResponseKey" = {
body = {
error = {
code = 100;
message = "(#100) The post's links must direct to the application's connect or canvas URL.";
type = OAuthException;
};
};
code = 400;
};
}
Please help, I have done more research online since my initial posting, and still can't find the answer.
Update Dec 17th:
I am using SDK 3.1.1. I'd like to avoid having to update, as I'm maintaining someone else's code.
Using me/feed, in a fbrequestconnection, any additional paramater aside from "message", crashes the app.
I've also tried linking the app to a test account with settings suggested by other stack overflow users viewable here
I've also disabled post streaming security
Other Questions
Am I missing something in linking up the app to Facebook?
Why won’t it detect that the “link” parameter is the same as the canvas url?
I've been struggling with posting to facebook wall too.
Why don't you use the facebook SDK instead of the API?
There are two ways to post to facebook wall using the SDK
Via Feed Dialog
or
Via Share Dialog
The Feed Dialog is very easy to implement and you can control what you want to post through the parameters you send, the only bad thing is that the parameters are limited.
The Share Dialog uses OpenGraph and requires the user to have the facebook APP installed, you also have to create an action in app developer page in facebook so your app knows what to do with that action.
The good part is that you can share almost all that you want.
I suggest you check the Feed Dialog if you want a simple facebook share, it's the easiest way.
Edit
NSString *message = [NSString stringWithFormat:#"%#%#/%#",domain,TypeName,[object alias]];
// Put together the dialog parameters
NSMutableDictionary *params =
[NSMutableDictionary dictionaryWithObjectsAndKeys:
#"TITLE", #"description",
message, #"link",
[object image],#"picture",
nil];
// Invoke the dialog
[FBWebDialogs presentFeedDialogModallyWithSession:nil
parameters:params
handler:
^(FBWebDialogResult result, NSURL *resultURL, NSError *error) {
if (error) {
// Error launching the dialog or publishing a story.
//NSLog(#"Error publishing story.");
} else {
if (result == FBWebDialogResultDialogNotCompleted) {
// User clicked the "x" icon
//NSLog(#"User canceled story publishing.");
} else {
// Handle the publish feed callback
NSDictionary *urlParams = [self parseURLParams:[resultURL query]];
if (![urlParams valueForKey:#"post_id"]) {
// User clicked the Cancel button
//NSLog(#"User canceled story publishing.");
} else {
// User clicked the Share button
NSString *msg = #"Partilhado com sucesso";
//NSLog(#"%#", msg);
// Show the result in an alert
[[[UIAlertView alloc] initWithTitle:#"Aviso"
message:msg
delegate:nil
cancelButtonTitle:#"OK!"
otherButtonTitles:nil]
show];
}
}
}
}];
I have found a services from Google which provides to access to Google APIs for various Google Services. I could set up a project in iPhone and create API access for iOS applications (via OAuth2.0) and native applications. I wanted to use the native API for my iPhone app. It API gives me email,fullname,firstname,lastname,google_id,gender,dob,profile_image. How do I use these in my iPhone Application, Any sample apps, snippets available?
Please help me.
Here is my code :
-(void) loadGmail_Login
{
NSString *keychainItemName = nil;
if ([self shouldSaveInKeychain]) {
keychainItemName = kKeychainItemName;
}
// For GTM applications, the scope is available as
NSString *scope = #"http://www.google.com/m8/feeds/";
// ### Important ###
// GTMOAuthViewControllerTouch is not designed to be reused. Make a new
// one each time you are going to show it.
// Display the autentication view.
GTMOAuthAuthentication *auth;
auth = [GTMOAuthViewControllerTouch authForGoogleFromKeychainForName:kKeychainItemName];
GTMOAuthViewControllerTouch *viewController = [[[GTMOAuthViewControllerTouch alloc]
initWithScope:scope
language:nil
appServiceName:keychainItemName
delegate:self
finishedSelector:#selector(viewController:finishedWithAuth:error:)] autorelease];
// You can set the title of the navigationItem of the controller here, if you want.
// Optional: display some html briefly before the sign-in page loads
NSString *html = #"<html><body bgcolor=silver><div align=center>Loading sign-in page...</div></body></html>";
[viewController setInitialHTMLString:html];
[[self navigationController] pushViewController:viewController animated:YES];
}
- (void)viewController:(GTMOAuthViewControllerTouch *)viewController
finishedWithAuth:(GTMOAuthAuthentication *)auth
error:(NSError *)error
{
if (error != nil)
{
// Authentication failed (perhaps the user denied access, or closed the
// window before granting access)
NSLog(#"Authentication error: %#", error);
NSData *responseData = [[error userInfo] objectForKey:#"data"]; // kGTMHTTPFetcherStatusDataKey
if ([responseData length] > 0) {
// show the body of the server's authentication failure response
NSString *str = [[[NSString alloc] initWithData:responseData
encoding:NSUTF8StringEncoding] autorelease];
NSLog(#"%#", str);
}
[self setAuthentication:nil];
}
else
{
// save the authentication object
[self setAuthentication:auth];
// Just to prove we're signed in, we'll attempt an authenticated fetch for the
// signed-in user
[self doAnAuthenticatedAPIFetch];
}
}
- (void)doAnAuthenticatedAPIFetch
{
NSString *urlStr;
// Google Contacts feed
//
// https://www.googleapis.com/oauth2/v2/userinfo
urlStr = #"http://www.google.com/m8/feeds/contacts/default/thin";
NSURL *url = [NSURL URLWithString:urlStr];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[mAuth authorizeRequest:request];
NSError *error = nil;
NSURLResponse *response = nil;
NSData *data = [NSURLConnection sendSynchronousRequest:request
returningResponse:&response
error:&error];
if (data) {
// API fetch succeeded
NSString *str = [[[NSString alloc] initWithData:data
encoding:NSUTF8StringEncoding] autorelease];
NSLog(#"API response: %#", str);
GGCXml_Adaptor *localAlphabetXMLParser = [[GGCXml_Adaptor alloc] init];
[localAlphabetXMLParser processBooksXML:data];
[localAlphabetXMLParser release];
// [self updateUI];
} else {
// fetch failed
NSLog(#"API fetch error: %#", error);
}
}
- (void)setAuthentication:(GTMOAuthAuthentication *)auth {
[mAuth autorelease];
mAuth = [auth retain];
}
First you will need to get token from Google API, For this 1st step you will have to follow this tutorial and in the end of this link there is whole source code for iOS for getting token from google API
http://technogerms.com/login-with-google-using-oauth-2-0-for-ios-xcode-objective-c/
Then in the next step you have to send that token to Google API to request user Data, I just needed the first step So I am sharing my searchings
Try this Tutorial and Source code Link.. It's works fine for me.
1. Tutorial Reference: http://technogerms.com/login-with-google-using-oauth-2-0-for-ios-xcode-objective-c/
2. Api Reference : https://code.google.com/apis/console/
3. Source code: https://github.com/emysa341/Login-with-gmail-google-g--using-oath-2.0-protocol/archive/master.zip
i think this will help anybody else
Follow the below steps to integrate gmail with your application .
1.Add following classes to you project .
GTMHTTPFetcher.h , GTMHTTPFetcher.m ,GTMOAuth2Authentication.h, GTMOAuth2Authentication.m,GTMOAuth2SignIn.h,GTMOAuth2SignIn.m,GTMOAuth2ViewControllerTouch.h,GTMOAuth2ViewControllerTouch.m,GTMOAuth2ViewTouch.xib,SBJSON.h , SBJSON.m
you will get these classes here : https://github.com/jonmountjoy/Force.com-iOS-oAuth-2.0-Example
Note : if you are working under ARC Environment then you have to disable the ARC for following files :
GTMHTTPFetcher.m , GTMOAuth2Authentication.m , GTMOAuth2SignIn.m, GTMOAuth2ViewControllerTouch.m
To disable ARC for source files in Xcode 4, select the project and the target in Xcode. Under the target "Build Phases" tab, expand the Compile Sources build phase, select the library source files, then press Enter to open an edit field, and type -fno-objc-arc as the compiler flag for those files.
2. add the following frameworks
security.framework , systemConfiguration.framework
3. Register your app to google api console …. here : https://code.google.com/apis/console
Then go to ApiAccess section , create client id for iOS app .
then you will get clientID, ClientSecret and RedirectUrl
**4. Now it's time for coding . . . .**
create a signIn button in your controller and set the action for that . Here when the user click the button SignInGoogleButtonClicked method gets called .
//import GTMOAuth2Authentication , GTMOAuth2ViewControllerTouch
#define GoogleClientID #"paster your client id"
#define GoogleClientSecret #"paste your client secret"
#define GoogleAuthURL #"https://accounts.google.com/o/oauth2/auth"
#define GoogleTokenURL #"https://accounts.google.com/o/oauth2/token"
-(void) SignInGoogleButtonClicked
{
NSURL * tokenURL = [NSURL URLWithString:GoogleTokenURL];
NSString * redirectURI = #"urn:ietf:wg:oauth:2.0:oob";
GTMOAuth2Authentication * auth;
auth = [GTMOAuth2Authentication authenticationWithServiceProvider:#"google"
tokenURL:tokenURL
redirectURI:redirectURI
clientID:GoogleClientID
clientSecret:GoogleClientSecret];
auth.scope = #"https://www.googleapis.com/auth/plus.me";
GTMOAuth2ViewControllerTouch * viewcontroller = [[GTMOAuth2ViewControllerTouch alloc] initWithAuthentication:auth
authorizationURL:[NSURL URLWithString:GoogleAuthURL]
keychainItemName:#"GoogleKeychainName" delegate:self
finishedSelector:#selector(viewController:finishedWithAuth:error:)];
[self.navigationController pushViewController:viewcontroller animated:YES];
}
//this method is called when authentication finished
- (void)viewController:(GTMOAuth2ViewControllerTouch * )viewController finishedWithAuth:(GTMOAuth2Authentication * )auth error:(NSError * )error
{
if (error != nil) {
UIAlertView * alert = [[UIAlertView alloc] initWithTitle:#"Error Authorizing with Google"
message:[error localizedDescription]
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
}
else
{
UIAlertView * alert = [[UIAlertView alloc] initWithTitle:#"Alert !"
message:#"success"
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
}
}
So I have a compiled and running Siphon app but it just won't make the calls.
I get:
registration error - default error message.
Full error is this:
15:04:02.032 pjsua_call.c Making call with acc #0 to sip:6476805821#voip5-2.acanac.com
15:04:02.032 pjsua_call.c .Unable to make call because account is not valid: Invalid operation (PJ_EINVALIDOP) [status=70013]
15:04:05.580 call.m Error making call: Invalid operation (PJ_EINVALIDOP) [status=70013]
But when I use the same account on a different SIP app, it works perfectly fine.
When pjsip calls sip_dial_with_uri(_sip_acc_id, [url UTF8String], &call_id);
_sip_acc_id is 0 since I believe it's the 0th account that's in the settings for siphon.
url is the correct phone number I'm trying to dial but shows something like:
sip:62304892#url.com
and call id is just a reference so I dunno if it's important.
When I look at other voip apps, they have a registration process. Where you enter you username, password, and sip server domain or ip.
For Siphon, this is done in the settings file. However, if "register or login" is done in Siphon's code or not, I'm not sure.
Could that be the problem?
This is the code that tries to make an actual call:
/** FIXME plutôt à mettre dans l'objet qui gère les appels **/
-(void) dialup:(NSString *)phoneNumber number:(BOOL)isNumber
{
pjsua_call_id call_id;
pj_status_t status;
NSString *number;
UInt32 hasMicro, size;
// Verify if microphone is available (perhaps we should verify in another place ?)
size = sizeof(hasMicro);
AudioSessionGetProperty(kAudioSessionProperty_AudioInputAvailable,
&size, &hasMicro);
/*if (!hasMicro)
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(#"No Microphone Available", #"SiphonApp")
message:NSLocalizedString(#"Connect a microphone to phone", #"SiphonApp")
delegate:nil
cancelButtonTitle:NSLocalizedString(#"OK", #"SiphonApp")
otherButtonTitles:nil];
[alert show];
[alert release];
return;
}*/
if (isNumber)
number = [self normalizePhoneNumber:phoneNumber];
else
number = phoneNumber;
if ([[NSUserDefaults standardUserDefaults] boolForKey:#"removeIntlPrefix"])
{
number = [number stringByReplacingOccurrencesOfString:#"+"
withString:#""
options:0
range:NSMakeRange(0,1)];
}
else
{
NSString *prefix = [[NSUserDefaults standardUserDefaults] stringForKey:
#"intlPrefix"];
if ([prefix length] > 0)
{
number = [number stringByReplacingOccurrencesOfString:#"+"
withString:prefix
options:0
range:NSMakeRange(0,1)];
}
}
// Manage pause symbol
NSArray * array = [number componentsSeparatedByString:#","];
[callViewController setDtmfCmd:#""];
if ([array count] > 1)
{
number = [array objectAtIndex:0];
[callViewController setDtmfCmd:[array objectAtIndex:1]];
}
if (!isConnected && [self wakeUpNetwork] == NO)
{
_phoneNumber = [[NSString stringWithString: number] retain];
if (isIpod)
{
UIAlertView *alertView = [[[UIAlertView alloc] initWithTitle:nil
message:NSLocalizedString(#"You must enable Wi-Fi or SIP account to place a call.",#"SiphonApp")
delegate:nil
cancelButtonTitle:NSLocalizedString(#"OK",#"SiphonApp")
otherButtonTitles:nil] autorelease];
[alertView show];
}
else
{
UIActionSheet *actionSheet = [[[UIActionSheet alloc] initWithTitle:NSLocalizedString(#"The SIP server is unreachable!",#"SiphonApp")
delegate:self
cancelButtonTitle:NSLocalizedString(#"Cancel",#"SiphonApp")
destructiveButtonTitle:nil
otherButtonTitles:NSLocalizedString(#"Cellular call",#"SiphonApp"),
nil] autorelease];
actionSheet.actionSheetStyle = UIActionSheetStyleDefault;
[actionSheet showInView: self.window];
}
return;
}
if ([self sipConnect])
{
NSRange range = [number rangeOfString:#"#"];
NSLog(#"%i", _sip_acc_id);
if (range.location != NSNotFound)
{
status = sip_dial_with_uri(_sip_acc_id, [[NSString stringWithFormat:#"sip:%#", number] UTF8String], &call_id);
}
else
status = sip_dial(_sip_acc_id, [number UTF8String], &call_id);
if (status != PJ_SUCCESS)
{
// FIXME
//[self displayStatus:status withTitle:nil];
const pj_str_t *str = pjsip_get_status_text(status);
NSString *msg = [[NSString alloc]
initWithBytes:str->ptr
length:str->slen
encoding:[NSString defaultCStringEncoding]];
[self displayError:msg withTitle:#"registration error"];
}
}
}
Also if anyone has a link to the Siphon app's code that's newer and maybe works better, I'd appreciate that as well.
More info:
in call.m file essentially this gets called:
status = pjsua_call_make_call(acc_id, &pj_uri, 0, NULL, NULL, call_id);
and here
acc_id = 0
pj_uri = char *-> "sip:6476805821#voip5-2.acanac.com"
pj_ssize_t -> 33
call_id = 803203976
I figured this out. Turns out, the siphon app wasn't registering the account.
The code below is important:
pj_status_t sip_connect(pj_pool_t *pool, pjsua_acc_id *acc_id)
{
// ID
acc_cfg.id.ptr = (char*) pj_pool_alloc(/*app_config.*/pool, PJSIP_MAX_URL_SIZE);
if (contactname && strlen(contactname))
acc_cfg.id.slen = pj_ansi_snprintf(acc_cfg.id.ptr, PJSIP_MAX_URL_SIZE,
"\"%s\"<sip:%s#%s>", contactname, uname, server);
else
acc_cfg.id.slen = pj_ansi_snprintf(acc_cfg.id.ptr, PJSIP_MAX_URL_SIZE,
"sip:%s#%s", uname, server);
if ((status = pjsua_verify_sip_url(acc_cfg.id.ptr)) != 0)
{
PJ_LOG(1,(THIS_FILE, "Error: invalid SIP URL '%s' in local id argument",
acc_cfg.id));
[app displayParameterError: #"Invalid value for username or server."];
return status;
}
// Registrar
acc_cfg.reg_uri.ptr = (char*) pj_pool_alloc(/*app_config.*/pool,
PJSIP_MAX_URL_SIZE);
acc_cfg.reg_uri.slen = pj_ansi_snprintf(acc_cfg.reg_uri.ptr,
PJSIP_MAX_URL_SIZE, "sip:%s", server);
if ((status = pjsua_verify_sip_url(acc_cfg.reg_uri.ptr)) != 0)
{
PJ_LOG(1,(THIS_FILE, "Error: invalid SIP URL '%s' in registrar argument",
acc_cfg.reg_uri));
[app displayParameterError: #"Invalid value for server parameter."];
return status;
}
...
more code here
...
}
This is where your account gets registered to a SIP server.
Make sure the sip_connect function gets called from the main application itself shown below:
/* */
- (BOOL)sipConnect
{
pj_status_t status;
if (![self sipStartup])
return FALSE;
//if ([self wakeUpNetwork] == NO)
// return NO;
NSLog(#"%i", _sip_acc_id);
//if (_sip_acc_id == PJSUA_INVALID_ID)
//{
self.networkActivityIndicatorVisible = YES;
if ((status = sip_connect(_app_config.pool, &_sip_acc_id)) != PJ_SUCCESS)
{
self.networkActivityIndicatorVisible = NO;
return FALSE;
}
//}
return TRUE;
}
in my case _sip_acc_id wasn't equal to PJSUA_INVALID_ID therefore sip_connect was never getting called.
Thanks for all of those who tried to solve it in their head? :)
You are unlikely to get any useful help unless you post a code snippet as well as error output (at minimum). More context, such as configuration info and relevant aspects of your network, will further improve your chances.
(I would have added this as a comment on the question, but don't yet have the required reputation.)