Parse iOS PFTwitterUtils linkUser: doesn't do anything - ios

So I am using Parse to link a user with their twitter account. In the app delegate I have the following:
[PFTwitterUtils initializeWithConsumerKey:CONSUMER_KEY consumerSecret:CONSUMER_SECRET];
Then the button which the user clicks to link the user to facebook calls the following:
-(IBAction)twitterConnectPressed{
NSLog(#"twitter");
[PFTwitterUtils linkUser:[PFUser currentUser] block:^(BOOL succeeded, NSError* error){
NSLog(#"haha");
if(succeeded){
UIAlertView* alert = [[UIAlertView alloc] initWithTitle:#"Done!" message:#"Connected with Twitter!" delegate:self cancelButtonTitle:#"okay" otherButtonTitles: nil];
[alert show];
self.fbButton.backgroundColor = [TGAPublic grey];
}else{
UIAlertView* alert = [[UIAlertView alloc] initWithTitle:#"Oops" message:error.userInfo[#"error"] delegate:self cancelButtonTitle:#"okay" otherButtonTitles: nil];
[alert show];
}
}];
}
However even though linkUser:block: is called it doesn't do anything at all. It doesn't create a pop up to log in to twitter like [PFFacebookUtils linkUser:] does and therefore doesn't end up calling the block either

PFTwitterUtils does not appear to handle all cases on iOS. In particular, if you do not have an account setup (Settings->Twitter) it does not fire up a web view and attempt to used web oauth. Conversely if you have multiple Twitter accounts configured (again in Settings) then it doesn't appear to fire up an action sheet to allow you to select which account you'd like to link.
There's a great tutorial on how to do these things which exposes an extension to PFFacebookUtils here: http://natashatherobot.com/ios-twitter-login-parse/
It does not do linking though, just login, but should be a good basis to add linking.

I've got similar problem with link/unlink methods for both PFFacebookUtils and PFTwitterUtils (v. 1.7.4).
The only way I managed to make it work was to replace them by, unfortunately, messing with internal Parse implementation of authData:
#import "TwitterAuthProvider.h"
#import "PFTwitterUtils.h"
#import "PFUser.h"
static NSString * const kTwitterKey = #"XXX";
static NSString * const kTwitterSecret = #"XXX";
#implementation TwitterAuthProvider
- (instancetype)init {
if ((self = [super init])) {
[PFTwitterUtils initializeWithConsumerKey:kTwitterKey consumerSecret:kTwitterSecret];
}
return self;
}
- (void)setAuthData:(id)twAuthData forUser:(PFUser *)user {
static NSString * const kParseAuthDataKey = #"authData";
static NSString * const kParseLinkedServiceNamesKey = #"linkedServiceNames";
static NSString * const kParseAuthProviderName = #"twitter";
NSMutableDictionary *authData = [[user valueForKey:kParseAuthDataKey] mutableCopy] ?: [NSMutableDictionary dictionary];
authData[kParseAuthProviderName] = twAuthData ?: [NSNull null];
[user setObject:authData forKey:kParseAuthDataKey];
[user setValue:authData forKey:kParseAuthDataKey];
NSMutableSet *linkedServices = [[user valueForKey:kParseLinkedServiceNamesKey] mutableCopy] ?: [NSMutableSet set];
if (twAuthData) {
[linkedServices addObject:kParseAuthProviderName];
} else {
[linkedServices removeObject:kParseAuthProviderName];
}
[user setValue:linkedServices forKey:kParseLinkedServiceNamesKey];
}
- (void)linkWithCompletion:(PFBooleanResultBlock)completion {
NSParameterAssert(completion != nil);
PFUser *user = [PFUser currentUser];
__weak typeof(self) weakSelf = self;
PF_Twitter *twitter = [PFTwitterUtils twitter];
[twitter authorizeWithSuccess:^(void) {
[weakSelf setAuthData:[self twitterAuthData] forUser:user];
[user saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
if (!succeeded) {
//revert
[weakSelf setAuthData:nil forUser:user];
}
completion(succeeded, error);
}];
} failure:^(NSError *error) {
completion(NO, error);
} cancel:^(void) {
completion(NO, nil);
}];
}
- (void)unlinkWithCompletion:(PFBooleanResultBlock)completion {
NSParameterAssert(completion != nil);
PFUser *user = [PFUser currentUser];
[self setAuthData:nil forUser:user];
[user saveInBackgroundWithBlock:completion];
}
- (NSDictionary *)twitterAuthData {
PF_Twitter *twitter = [PFTwitterUtils twitter];
return #{
#"auth_token" : twitter.authToken,
#"auth_token_secret": twitter.authTokenSecret,
#"consumer_key": kTwitterKey,
#"consumer_secret": kTwitterSecret,
#"id": twitter.userId,
#"screen_name": twitter.screenName,
};
}
#end

Related

Firebase Upload Image to Storage During User Registration

I'm new to Firebase, and I have been following their documentation here.
However, nothing I have tried seems to work.
What I am trying to do:
1) Register a user -Works
2) Have the user choose a profile picture during the registration process -Doesn't work.
The code:
- (void) registerNewUser:(FIRUser *)user
{
FIRUser *currentUser = [FIRAuth auth].currentUser;
NSString *email = emailAddressTxtField.text;
NSString *password = passwordTxtField.text;
NSString *username = usernameTxtField.text;
[[FIRAuth auth]
createUserWithEmail:email
password:password
completion:^(FIRUser *_Nullable user,
NSError *_Nullable error)
{
if (error)
{
NSLog(#"%#", error.localizedDescription);
return;
}
else
{
////ASSIGN NEW USER THEIR NAME////
self.databaseRef = [[FIRDatabase database] reference];
[[[databaseRef child:#"users"] child:user.uid]
setValue:#{#"name": username}];
}
}];
////ESTABLISHED A USER, SO LET'S ASSIGN THEIR PIC TO THEM////
if (profilePicImageView.image)
{
FIRStorageReference *profilePicRef = [[storageRef child:#"images/profilePicture.jpg"] child:currentUser.uid];
FIRStorageMetadata *metadata = [[FIRStorageMetadata alloc] init];
metadata.contentType = #"image/jpeg";
NSData *imageData = UIImageJPEGRepresentation(self.profilePicImageView.image, 0.8);
NSLog(#"metadata from image: %#", metadata);
[profilePicRef putData:imageData metadata:metadata completion:^(FIRStorageMetadata *metadata, NSError *error)
{
if (error != nil)
{
NSString *profileImageURL = metadata.downloadURL.absoluteString;
NSLog(#"Profile Image URL from image: %#", profileImageURL);
[ProgressHUD showSuccess:[NSString stringWithFormat:#"%# Successfully Registered!!", username]];
[self.segmentedLoginRegister setSelectedSegmentIndex:0];
[self checkSegmentedControl];
[ProgressHUD showSuccess:[NSString stringWithFormat:#"Welcome %#!", username]];
}
else
{
NSLog(#"Failed to Register User with profile image");
}
}];
}
}
Additional Information:
Photos are coming only from the camera roll of the user's device
Debug area prints:
[Generic] Creating an image format with an unknown type is an error
My guess is that profilePicImageView.image doesn't actually contain a valid image object.
HOW TO REGISTER A USER
Let's assume that you have 3 textfields to register a user. You have a usernameTextfield, an emailTextField, and a passwordTextfield. We also want to have a profilePicture associated with this user. So we first:
Established a method to save our values for our User to the Firebase Database:
-(void) saveValuesForUser:(FIRUser *) user
{
NSString *username = usernameTxtField.text;
self.databaseRef = [[FIRDatabase database] reference];
[[[databaseRef child:#"users"] child:user.uid]
setValue:#{#"Name": username, #"Profile Picture": profileImageURL}];
}
The profileImageURL above is an NSString that you can create above your implementation of your view controller, but we also should create a UIImage that we can access throughout the ViewController:
#import "ViewController.h"
#import Photos;
#interface ViewController ()
#end
NSString *profileImageURL;
UIImage *profileImage;
#implementation ViewController
I'm guessing that you know how to launch the camera roll off from a UIButton but in case you do not, let's call these methods so that when our user taps the button to choose their image that it get's set to our profilePicture.imageView:
- (IBAction)chooseImageAction:(id)sender
{
UIImagePickerController *picker = [[UIImagePickerController alloc] init];
picker.delegate = self;
picker.allowsEditing = YES;
picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
[self presentViewController:picker animated:YES completion:NULL];
}
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info
{
picker.delegate = self;
profileImage = info[UIImagePickerControllerEditedImage];
profilePicImageView.image = profileImage;
[self dismissViewControllerAnimated:NO completion:nil];
}
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker
{
[picker dismissViewControllerAnimated:YES completion:NULL];
}
Now we're cooking with fire! Now that we have the image the user wants to upload for their profilePicture, let's create a method to save it as an NSURL to our Firebase Database:
- (void) saveProfileImage
{
FIRUser *currentUser = [FIRAuth auth].currentUser;
NSString *username = usernameTxtField.text;
if (profilePicImageView.image != nil)
{
FIRStorage *storage = [FIRStorage storage];
storageRef = [storage referenceForURL:#"gs://PUTYOURFIREBASEHERE.appspot.com"];
NSString *imageID = [[NSUUID UUID] UUIDString];
NSString *imageName = [NSString stringWithFormat:#"Profile Pictures/%#.jpg",imageID];
FIRStorageReference *profilePicRef = [storageRef child:imageName];
FIRStorageMetadata *metadata = [[FIRStorageMetadata alloc] init];
metadata.contentType = #"image/jpeg";
NSData *imageData = UIImageJPEGRepresentation(self.profilePicImageView.image, 0.8);
[profilePicRef putData:imageData metadata:metadata completion:^(FIRStorageMetadata *metadata, NSError *error)
{
if (!error)
{
profileImageURL = metadata.downloadURL.absoluteString;
[self saveValuesForUser: currentUser];
}
else if (error)
{
NSLog(#"Failed to Register User with profile image");
}
}];
}
}
IMPORTANT: Make sure you insert your gs:// reference for the value of storageRef! You can find this on your Firebase Console under Storage.
Now that we have the method to save the user's profile picture, let's create a method to Register the new user that we can call it on our IBAction:
- (void) registerNewUser
{
NSString *email = emailAddressTxtField.text;
NSString *password = passwordTxtField.text;
[[FIRAuth auth]
createUserWithEmail:email
password:password
completion:^(FIRUser *_Nullable user,
NSError *_Nullable error)
{
if (error)
{
NSLog(#"%#", error.localizedDescription);
return;
}
else
{
[self saveProfileImage];
}
}];
}
Oh thats nice! Now, let's call that method on our button, so that when the user taps the Register button on our UI, that it get's called:
- (IBAction)registerUserAction:(id)sender
{
[self registerNewUser];
}
Note: Make sure that in your ViewController.h file that you are setting the appropriate delegates:
#interface ViewController : UIViewController <UIImagePickerControllerDelegate, UINavigationControllerDelegate, UITextFieldDelegate>

xcode 6: TwitterKit not keeping session open after Authentication

I'm calling up a session in my LoginViewController as seen below. The problem is that, after it authenticates and closes the popupview... the session returns nil. So it initially reaches out to the api and starts a session (the first log records nil as the session is open and the second log records "Signed in as..." with the username) then when it closes the login view it records nil again. Not exactly use what I could be doing wrong...
Could it be because I'm using TWTRSession* session to check the session? Could that be logging me off? Or is it related to me closing the popupview?
I do essentially the same thing with my facebook login but the facebook session stays open until I logout...
- (void)viewDidLoad
{
[super viewDidLoad];
self.email.delegate = self;
self.pass.delegate = self;
//self.view.frame = CGRectMake(self.bounds.size.width, self.bounds.size.height);
[Fabric with:#[[Twitter sharedInstance]]];
TWTRSession* session;
if (session) {
NSLog(#"Early bird %#", [session userName]);
[self closePopup];
}
else {
NSLog(#"No dice");
}
/*
TWTRLogInButton *logInButton = [TWTRLogInButton buttonWithLogInCompletion:^(TWTRSession *session, NSError *error) {
// play with Twitter session
}];
logInButton.center = self.view.center;
[self.view addSubview:logInButton];
*/
TWTRLogInButton* logInButton = [TWTRLogInButton
buttonWithLogInCompletion:
^(TWTRSession* session, NSError* error) {
if (session) {
NSLog(#"signed in as %#", [session userName]);
[self closePopup];
} else {
NSLog(#"error: %#", [error localizedDescription]);
}
}];
I decided to include my actionsheet as well so you could see how I'm handling the login/logout situation:
- (void)sheet: (id) sender {
NSString *email = [[NSUserDefaults standardUserDefaults] objectForKey:#"email"];
UIActionSheet *sheet;
TWTRSession *session;
//if ([FBSDKAccessToken currentAccessToken]) {
if (email == nil && [FBSDKAccessToken currentAccessToken] == nil && session == nil) {
sheet = [[UIActionSheet alloc] initWithTitle:#"Profile"
delegate:nil // Can be another value but will be overridden when showing with handler.
cancelButtonTitle:#"Cancel"
destructiveButtonTitle:#"Login"
otherButtonTitles:nil];
}
else
{
sheet = [[UIActionSheet alloc] initWithTitle:#"Profile"
delegate:nil // Can be another value but will be overridden when showing with handler.
cancelButtonTitle:#"Cancel"
destructiveButtonTitle:#"Logout"
otherButtonTitles:#"User page", nil];
}
[sheet showInView:self.view
handler:^(UIActionSheet *actionSheet, NSInteger buttonIndex) {
if (buttonIndex == [actionSheet cancelButtonIndex]) {
NSLog(#"Cancel button index tapped");
} else if (buttonIndex == [actionSheet destructiveButtonIndex]) {
if (email == nil && [FBSDKAccessToken currentAccessToken] == nil && session == nil) {
LoginViewController *loginView = [[LoginViewController alloc] initWithNibName:#"LoginView" bundle:[NSBundle mainBundle]];
//[self.view modalViewController:loginView animated:YES];
//[self presentModalViewController:loginView animated:YES];
//[self.navigationController pushViewController:loginView animated:YES];
loginView.delegate = (id) self;
[self presentPopupViewController:loginView animationType:MJPopupViewAnimationSlideTopBottom];
NSLog(#"Login View");
}
else
{
[[NSUserDefaults standardUserDefaults] setObject:nil forKey:#"email"];
FBSDKLoginManager *logout = [[FBSDKLoginManager alloc] init];
[logout logOut];
}
} else {
NSLog(#"Button %i tapped", buttonIndex);
if (buttonIndex == 1) {
UserViewController * userView = [[UserViewController alloc] initWithNibName:#"UserView" bundle:[NSBundle mainBundle]];
[userView setUEmail:email];
[self presentViewController:userView animated:YES completion:nil];
}
}
}];
}
So I ended up creating my own custom IBAction to handle twitter logins. This works much better. Basically you just have to be careful with how you check if a session is active:
-(IBAction)twlogin:(id)sender
{
[Fabric with:#[[Twitter sharedInstance]]];
[[Twitter sharedInstance] logInWithCompletion:^
(TWTRSession *session, NSError *error) {
if (session) {
NSLog(#"signed in as %#", [session userName]);
TWTRShareEmailViewController* shareEmailViewController =
[[TWTRShareEmailViewController alloc]
initWithCompletion:^(NSString* email2, NSError* error) {
NSLog(#"Email %#, Error: %#", email2, error);
}];
[self presentViewController:shareEmailViewController
animated:YES
completion:nil];
[self closePopup];
NSLog(#"session check %#", [session userName]);
} else {
NSLog(#"error: %#", [error localizedDescription]);
}
}];
[[Twitter sharedInstance] logOut];
}
As you can see TWTR *session has to be included with Twitter shared instance like so:
[[Twitter sharedInstance] logInWithCompletion:^
(TWTRSession *session, NSError *error) {
I didn't do that before, and that's why it wasn't working. Hopefully this helps someone. (now if someone would help me getting Twitter emails to work... that would be greatly appreciated...)

Warning inside code when updating Parse object

I am using the following code to update a Parse object as button action:
-(IBAction)sendPressed:(id)sender
{
NSLog(#"boton subir cadena pulsado");
loadingSpinner.hidden = NO;
[loadingSpinner startAnimating];
//Upload a new picture
NSData *pictureData = UIImagePNGRepresentation(self.chainPhoto.image);
PFFile *file = [PFFile fileWithName:#"img" data:pictureData];
[file saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
if (succeeded){
NSLog(#"IMAGEN CARGADA");
PFQuery *query = [PFQuery queryWithClassName:#"cadenas"];
// Retrieve the object by id
[query getObjectInBackgroundWithId: chain.objectId block:^(PFObject *imageObject, NSError *error)
{
[imageObject setObject:file forKey:#"image"];
[imageObject setObject:self.commentTextField.text forKey:#"chain_name"];
[imageObject saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
if (succeeded){
//Go back to the wall
[self.navigationController popViewControllerAnimated:YES];
}
else{
NSString *errorString = [[error userInfo] objectForKey:#"error"];
[self showErrorView:errorString];
}
}];
}
ERROR HERE--> else
{
NSString *errorString = [[error userInfo] objectForKey:#"error"];
[self showErrorView:errorString];
}
}
[loadingSpinner stopAnimating];
//loadingSpinner.hidden = YES;
//self.commentTextField.text =#" ";
self.progress_block.hidden = YES;
// self.imageView.image = [UIImage imageNamed:#"no-image.jpg"];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Restaurant Chain changed with success"
message:#"You can now go back to the list."
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
} progressBlock:^(int percentDone) {
self.progress_block.hidden =NO;
self.progress_block.progress = (float) percentDone/100+progressValue;
}];
}
In the line that I have marked as ERROR HERE in the code, there is an error warning (Expected ":"), but I can't find out why.
Any help is welcome.
From the looks of it, you never closed the query bracket:
PFQuery getObjectInBackground.... {
but never closed it using the proper syntax or it looks like you have an extra bracket }. For better practice, you should use proper indentation with if statements or else complications can happen like this. You get lost in the code because you don't know where a statement begins or ends
You should close it after the else statement so:
} ERROR HERE--> else {
NSString *errorString = [[error userInfo] objectForKey:#"error"];
[self showErrorView:errorString];
//stop animating and other stuff
}
}];
I can't troubleshoot because i'm on my iPhone but I would suggest going back and using proper indentation so you can catch your culprit

Upload Facebook Photo And Auto Log User Out (Kiosk App)

I have an iPad app designed for use in a kiosk environment.
The user flow should be
Take Photo
Choose photo from iPad Album view
Share to Facebook and / or Twitter
Automatically log user out after image has been posted
I have the auto-logout of Twitter working properly, my issue is with the Facebook portion.
I have implemented the Graph API for internal testing, and would love to be able to post a complete story this way, but I don't think there is a way to log out from the Facebook app once the authorization and post is complete.
For a fallback, I can use the Feed Dialog and auto-logout from there, but as far as I can tell, there is no way to upload a local image for sharing to Facebook from there.
My Facebook Sharing code is as follows:
- (IBAction)facebookShare:(id)sender {
/// Package the image inside a dictionary
NSArray* image = #[#{#"url": self.mergeImages, #"user_generated": #"true"}];
// Create an object
id<FBGraphObject> object =
[FBGraphObject openGraphObjectForPostWithType:#"me/feed:photo"
title:#"a photo"
image:self.mergeImages
url:nil
description:nil];
// Create an action
id<FBOpenGraphAction> action = (id<FBOpenGraphAction>)[FBGraphObject graphObject];
// Set image on the action
[action setObject:image forKey:#"image"];
// Link the object to the action
[action setObject:object forKey:#"photo"];
// Hardcode the location based on Facebook Place ID
id<FBGraphPlace> place = (id<FBGraphPlace>)[FBGraphObject graphObject];
[place setId:#"279163865580772"]; // Singley + Mackie
[action setPlace:place];
// Check if the Facebook app is installed and we can present the share dialog
FBOpenGraphActionShareDialogParams *params = [[FBOpenGraphActionShareDialogParams alloc] init];
params.action = action;
params.actionType = #"me/feed:share";
// If the Facebook app is installed and we can present the share dialog
if([FBDialogs canPresentShareDialogWithOpenGraphActionParams:params]) {
// Show the share dialog
[FBDialogs presentShareDialogWithOpenGraphAction:action
actionType:#"photo_overlay:share"
previewPropertyName:#"photo"
handler:^(FBAppCall *call, NSDictionary *results, NSError *error) {
if(error) {
// An error occurred, we need to handle the error
// See: https://developers.facebook.com/docs/ios/errors
// NSLog([NSString stringWithFormat:#"Error publishing story: %#", error.description]);
} else {
// Success
NSLog(#"result %#", results);
}
}];
// If the Facebook app is NOT installed and we can't present the share dialog
} else {
// Put together the Feed dialog parameters
NSMutableDictionary *params = [NSMutableDictionary dictionaryWithObjectsAndKeys:
#"name",
#"caption",
#"description",
#"link",
#"picture",
nil];
// Show the feed dialog
[FBWebDialogs presentFeedDialogModallyWithSession:nil
parameters:params
handler:^(FBWebDialogResult result, NSURL *resultURL, NSError *error) {
if (error) {
// An error occurred, we need to handle the error
// See: https://developers.facebook.com/docs/ios/errors
// NSLog([NSString stringWithFormat:#"Error publishing story: %#", error.description]);
} else {
if (result == FBWebDialogResultDialogNotCompleted) {
// User cancelled.
NSLog(#"User cancelled.");
} else {
// Handle the publish feed callback
NSDictionary *urlParams = [self parseURLParams:[resultURL query]];
if (![urlParams valueForKey:#"post_id"]) {
// User cancelled.
NSLog(#"User cancelled.");
} else {
// User clicked the Share button
NSString *result = [NSString stringWithFormat: #"Posted story, id: %#", [urlParams valueForKey:#"post_id"]];
NSLog(#"result %#", result);
}
}
}
// Auto log the user out
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSLog(#"defaults fbDidLogout ........%#",defaults);
if ([defaults objectForKey:#"FBAccessTokenKey"])
{
[defaults removeObjectForKey:#"FBAccessTokenKey"];
[defaults removeObjectForKey:#"FBExpirationDateKey"];
[defaults synchronize];
}
NSHTTPCookie *cookie;
NSHTTPCookieStorage *storage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
for (cookie in [storage cookies])
{
NSString* domainName = [cookie domain];
NSRange domainRange = [domainName rangeOfString:#"facebook"];
if(domainRange.length > 0)
{
[storage deleteCookie:cookie];
}
}
[FBSession.activeSession closeAndClearTokenInformation];
}];
}
}
// A function for parsing URL parameters.
- (NSDictionary*)parseURLParams:(NSString *)query {
NSArray *pairs = [query componentsSeparatedByString:#"&"];
NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
for (NSString *pair in pairs) {
NSArray *kv = [pair componentsSeparatedByString:#"="];
NSString *val =
[kv[1] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
params[kv[0]] = val;
}
return params;
}
I have searched Stack Overflow far and wide for an answer to this, but have found no solutions.
I was finally able to figure this out! Posting the answer here to hopefully benefit others who are in the same situation.
First, add the following to your AppDelegate.m:
-(BOOL) application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
return [FBAppCall handleOpenURL:url sourceApplication:sourceApplication fallbackHandler:^(FBAppCall *call) {
// Facebook SDK * App Linking *
// For simplicity, this sample will ignore the link if the session is already
// open but a more advanced app could support features like user switching.
if (call.accessTokenData) {
if ([FBSession activeSession].isOpen) {
NSLog(#"INFO: Ignoring app link because current session is open.");
}
else {
[self handleAppLink:call.accessTokenData];
}
}
}];
}
// Helper method to wrap logic for handling app links.
- (void)handleAppLink:(FBAccessTokenData *)appLinkToken {
// Initialize a new blank session instance...
FBSession *appLinkSession = [[FBSession alloc] initWithAppID:nil
permissions:nil
defaultAudience:FBSessionDefaultAudienceNone
urlSchemeSuffix:nil
tokenCacheStrategy:[FBSessionTokenCachingStrategy nullCacheInstance] ];
[FBSession setActiveSession:appLinkSession];
// ... and open it from the App Link's Token.
[appLinkSession openFromAccessTokenData:appLinkToken
completionHandler:^(FBSession *session, FBSessionState status, NSError *error) {
// Forward any errors to the FBLoginView delegate.
if (error) {
//[self.loginViewController loginView:nil handleError:error];
}
}];
}
Wherever you are calling the posting action in your app, add this line to your header file:
#property (strong, nonatomic) FBRequestConnection *requestConnection;
And the following to your implementation file:
#synthesize requestConnection;
- (IBAction)facebookShare:(id)sender {
NSArray *permissions = [[NSArray alloc] initWithObjects:
#"publish_actions", #"publish_checkins", nil];
UIImage *img = self.facebookImage;
[FBSession openActiveSessionWithPublishPermissions:permissions
defaultAudience:FBSessionDefaultAudienceEveryone allowLoginUI:YES
completionHandler:^(FBSession *session,FBSessionState s, NSError *error) {
[FBSession setActiveSession:session];
if (!error) {
// Now have the permission
[self processPostingImage:img WithMessage:#"Enter_your_message_here"];
} else {
// Facebook SDK * error handling *
// if the operation is not user cancelled
if (error.fberrorCategory != FBErrorCategoryUserCancelled) {
[self presentAlertForError:error];
}
}
}];
}
-(void)logout {
[FBSession.activeSession closeAndClearTokenInformation];
[FBSession.activeSession close];
[FBSession setActiveSession:nil];
}
- (void)processPostingImage:(UIImage *) img WithMessage:(NSString *)message {
FBRequestConnection *newConnection = [[FBRequestConnection alloc] init];
FBRequestHandler handler =
^(FBRequestConnection *connection, id result, NSError *error) {
// output the results of the request
[self requestCompleted:connection forFbID:#"me" result:result error:error];
};
FBRequest *request=[[FBRequest alloc] initWithSession:FBSession.activeSession graphPath:#"me/photos" parameters:[NSDictionary dictionaryWithObjectsAndKeys:UIImageJPEGRepresentation(img, 0.7),#"source",message,#"message",#"{'value':'EVERYONE'}",#"privacy", nil] HTTPMethod:#"POST"];
[newConnection addRequest:request completionHandler:handler];
[self.requestConnection cancel];
self.requestConnection = newConnection;
[newConnection start];
}
// FBSample logic
// Report any results. Invoked once for each request we make.
- (void)requestCompleted:(FBRequestConnection *)connection
forFbID:fbID
result:(id)result
error:(NSError *)error
{
// not the completion we were looking for...
if (self.requestConnection &&
connection != self.requestConnection)
{
return;
}
// clean this up, for posterity
self.requestConnection = nil;
if (error)
{
}
else
{
[self logout];
};
}
- (void) presentAlertForError:(NSError *)error {
// Facebook SDK * error handling *
// Error handling is an important part of providing a good user experience.
// When fberrorShouldNotifyUser is YES, a fberrorUserMessage can be
// presented as a user-ready message
if (error.fberrorShouldNotifyUser) {
// The SDK has a message for the user, surface it.
[[[UIAlertView alloc] initWithTitle:#"Something Went Wrong"
message:error.fberrorUserMessage
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil] show];
} else {
}
}
Note:
To make this work with auto-logout, you also have to disable Safari on the device. This can be done by going to Settings > General > Restrictions > Allow Safari > Off. Once that is turned off, the Facebook IBAction will popup a UIWebView inside the app itself. When tapped, the current user can enter their Facebook credentials, then the app will post the image, and log the user out so the next user can use the app without having access to the previous user's Facebook details.

Need suggestion to integrate gmail account in iOS developlment

I am new to iOS programming, and just want to do something fun.
I want to develop a mail client app for iPhone, it can add email accounts such as gmail and Yahoo and so on. I searched online for a while and also find some answers, before I dive into the details I just want someone who has similar experience give me some suggestions about which method is the best.
thanks
I have recently implemented gmail api to fetch gmail contacts and their email in my tableview. Gmail api is depricated, thats why you might have not got any proper documentation for that.
To implement gmail use libGDataTouchStaticLib.a library, with Gdata headers (search on google for that otherwise send me your email i will send you its zip).
The code to get gmail details are as follows
- (void)getGoogleContacts {
GDataServiceGoogleContact *service = [self contactService];
GDataServiceTicket *ticket;
BOOL shouldShowDeleted = TRUE;
// request a whole buncha contacts; our service object is set to
// follow next links as well in case there are more than 2000
const int kBuncha = 2000;
NSURL *feedURL = [GDataServiceGoogleContact contactFeedURLForUserID:kGDataServiceDefaultUser];
GDataQueryContact *query = [GDataQueryContact contactQueryWithFeedURL:feedURL];
[query setShouldShowDeleted:shouldShowDeleted];
[query setMaxResults:kBuncha];
ticket = [service fetchFeedWithQuery:query
delegate:self
didFinishSelector:#selector(contactsFetchTicket:finishedWithFeed:error:)];
[self setContactFetchTicket:ticket];
}
- (void)setContactFetchTicket:(GDataServiceTicket *)ticket {
mContactFetchTicket = ticket;
}
- (GDataServiceGoogleContact *)contactService {
static GDataServiceGoogleContact* service = nil;
if (!service) {
service = [[GDataServiceGoogleContact alloc] init];
[service setShouldCacheResponseData:YES];
[service setServiceShouldFollowNextLinks:YES];
}
// update the username/password each time the service is requested
NSString *username = [txtUserName text];
NSString *password = [txtPasswrod text];
[service setUserCredentialsWithUsername:username
password:password];
return service;
}
// contacts fetched callback
- (void)contactsFetchTicket:(GDataServiceTicket *)ticket
finishedWithFeed:(GDataFeedContact *)feed
error:(NSError *)error {
if (error) {
NSDictionary *userInfo = [error userInfo];
NSLog(#"Contacts Fetch error :%#", [userInfo objectForKey:#"Error"]);
if ([[userInfo objectForKey:#"Error"] isEqual:#"BadAuthentication"]) {
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Error!"
message:#"Authentication Failed"
delegate:self
cancelButtonTitle:#"Ok"
otherButtonTitles:nil, nil];
[alertView show];
} else {
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Error!"
message:#"Failed to get Contacts."
delegate:self
cancelButtonTitle:#"Ok"
otherButtonTitles:nil, nil];
[alertView show];
}
} else {
NSArray *contacts = [feed entries];
NSLog(#"Contacts Count: %d ", [contacts count]);
[mutAryGoogleContacts removeAllObjects];
for (int i = 0; i < [contacts count]; i++) {
NSMutableDictionary *aDictContactDetails=[NSMutableDictionary dictionary];
GDataEntryContact *contact = [contacts objectAtIndex:i];
// Email
GDataEmail *email = [[contact emailAddresses] objectAtIndex:0];
NSString* ContactEmail = [email address];
if (ContactEmail) {
[aDictContactDetails setObject:ContactEmail forKey:#"email"];
// Name
NSString *ContactName = [[[contact name] fullName] contentStringValue];
if (ContactName) {
[aDictContactDetails setObject:ContactName forKey:#"friendName"];
}
[mutAryGoogleContacts addObject:aDictContactDetails];
}
}
//Push to next vc or do whatever you want
}
}

Resources