I'm using STTwitterto interface with Twitter in an iOS app I'm changing for someone. When I call the twitter authorization page for the first time with the following code:
- (void)newUser
{
[[NetworkManager sharedInstance] resetTwitterAPI];
[[[NetworkManager sharedInstance] twitterAPI] postTokenRequest:^(NSURL *url, NSString *oauthToken) {
[[UIApplication sharedApplication] openURL:url];
} oauthCallback:#"tweepr://twitter_access_token" errorBlock:^(NSError *error) {
NSLog(#"Error %s", __PRETTY_FUNCTION__);
}];
}
* Which, in turn, calls this:
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
{
if (![[url scheme] isEqualToString:#"tweepr"]) {
return NO;
}
NSDictionary *d = [self parametersDictionaryFromQueryString:[url query]];
NSString *token = d[#"oauth_token"];
NSString *verifier = d[#"oauth_verifier"];
[[UserLoadingRoutine sharedRoutine] setOAuthToken:token verifier:verifier];
return YES;
}
* Which finally calls this:
- (void)setOAuthToken:(NSString *)token verifier:(NSString *)verifier
{
[[[NetworkManager sharedInstance] twitterAPI] postAccessTokenRequestWithPIN:verifier successBlock:^(NSString *oauthToken, NSString *oauthTokenSecret, NSString *userID, NSString *screenName) {
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
dict[#"nickname"] = screenName;
dict[#"token"] = oauthToken;
dict[#"secret"] = oauthTokenSecret;
dict[#"user_id"] = userID;
self.userDict = dict;
NSMutableArray *users = [self.availableUsers mutableCopy];
if (![users containsObject:dict]) {
[users addObject:dict];
}
self.availableUsers = [users copy];
[[NSUserDefaults standardUserDefaults] setObject:self.availableUsers forKey:#"availableUsers"];
[[NSUserDefaults standardUserDefaults] synchronize];
[self selectUserWithIdentifier:dict[#"nickname"]];
} errorBlock:^(NSError *error) {
NSLog(#"Error");
}];
}
The twitter authorization page, the first time it comes up, has login and password fields to fill in as shown below at This Screenshot. If I bring the authorization page up again via the above code to authorize under a different user, This Screenshot appears and I need to sign out on the top. Is there a way to do this progmatically?
Append &force_login=1 to the URL string in -[STTwitterOAuth postTokenRequest:oauthCallback:errorBlock:].
Let me know if it works.
Related
I suppose that this is duplicate but I can not figure it out.
I have to call other app from my iOS app using openUrl method. After finishing its work the other app must return to my app using the same method. I figure out how to call the other App and its open my App too. My problem is how to intercept the return to my App. I need to check the value from query string.
I find that method handleOpenURL intercepts return and I can handle my query string.
And here I am stuck - how to use that info inside my ViewController? I set breakpoint in viewDidLoad but it was not hit. Which method I have to use?
EDIT:
My Code is (inside AppDelegate):
- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url {
NSLog(#"url recieved: %#", url);
NSLog(#"query string: %#", [url query]);
NSLog(#"host: %#", [url host]);
NSLog(#"url path: %#", [url path]);
NSDictionary *dict = [self parseQueryString:[url query]];
NSLog(#"query dict: %#", dict);
return YES;
}
- (NSDictionary *)parseQueryString:(NSString *)query {
NSMutableDictionary *dict = [[NSMutableDictionary alloc] initWithCapacity:6];
NSArray *pairs = [query componentsSeparatedByString:#"&"];
for (NSString *pair in pairs) {
NSArray *elements = [pair componentsSeparatedByString:#"="];
NSString *key = [[elements objectAtIndex:0] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSString *val = [[elements objectAtIndex:1] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
[dict setObject:val forKey:key];
}
return dict;
}
Which works fine.
Inside my ViewController (VC):
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
[self setNeedsStatusBarAppearanceUpdate];
// Instantiate App singleton
singApp = [PESsingApplication sharedInstance];
#try {
// Localize resources using currently saved setting for language
[self setLocalizedResources];
// Init visual buttons
[self baseInit];
// Add code for keyboard management
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardShow:)
name:UIKeyboardWillShowNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardHide:)
name:UIKeyboardWillHideNotification
object:nil];
CGRect screenRect = [[UIScreen mainScreen] bounds];
_screenHeight = screenRect.size.height;
_screenWidth = screenRect.size.width;
}
#catch (NSException *exception) {
[self throwUnknownException:exception];
}
}
-(UIStatusBarStyle)preferredStatusBarStyle{
return UIStatusBarStyleLightContent;
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
My url:
URL identifier: xx.mydomain.MyUrlScheme
URL shcemes: MyUrlScheme
I have breakpoints inside my VC (on each of the method shown above).
I use following string to call other app: #"otherApp://openApp?param1=value1&callbackUrl=MyUrlScheme";
They call me from the otherApp using callbackUrl param.
You need to make your own custom URL, please look below
How to implement Custom URL Scheme
Defining your app's custom URL scheme is all done in the Info.plist file. Click on the last line in the file and then click the "+" sign off to the right to add a new line. Select URL Types for the new item. Once that's added, click the grey arrow next to "URL Types" to show "Item 0". Set your URL identifier to a unique string - something like com.yourcompany.yourappname.
After you've set the URL identifier, select that line and click the "+" sign again, and add a new item for URL Schemes. Then click the grey arrow next to "URL Schemes" to reveal "Item 0". Set the value for Item 0 to be your URL scheme name.
Handling Custom URL Calls
In order for your app to respond when it receives a custom URL call, you must implement the application:handleOpenURL method in the application delegate class:
- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url {
// your code
}
Parsing the Custom URL
There are several parts to a URL:
scheme://host/path?query
The parts to the URL can be retrieved through the NSURL object that is passed into the application:handleOpenURL method. If you have a fairly simple URL naming scheme and want to allow access to specific pages/keys, you can just use the host name:
Custom URL Value of [url host]:
myapp://page1 page1
myapp://page2 page2
myapp://otherPage otherPage
To pass data into your app, you'll want to use the query string. Here's a simple method for parsing the query string from the url:
- (NSDictionary *)parseQueryString:(NSString *)query {
NSMutableDictionary *dict = [[[NSMutableDictionary alloc] initWithCapacity:6] autorelease];
NSArray *pairs = [query componentsSeparatedByString:#"&"];
for (NSString *pair in pairs) {
NSArray *elements = [pair componentsSeparatedByString:#"="];
NSString *key = [[elements objectAtIndex:0] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSString *val = [[elements objectAtIndex:1] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
[dict setObject:val forKey:key];
}
return dict;
}
Testing The Custom URL
You can easily test your URL scheme in the simulator. Just add a test button to one of your views, and implement the IBAction method for it as follows:
- (IBAction)getTest:(id)sender {
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:#"myappscheme://test_page/one?token=12345&domain=foo.com"]];
}
Then in your app delegate, implement the application:handleOpenURL method:
- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url {
NSLog(#"url recieved: %#", url);
NSLog(#"query string: %#", [url query]);
NSLog(#"host: %#", [url host]);
NSLog(#"url path: %#", [url path]);
NSDictionary *dict = [self parseQueryString:[url query]];
NSLog(#"query dict: %#", dict);
return YES;
}
Finally if you are looking method to receive your data anywhere you can use this two scenario.
You can simple use Local notification or NSUserDefault
NSUserDefault
- (BOOL)application:(UIApplication *)application handleopenURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
{
NSUserDefaults *userDefaults=[[NSUserDefaults alloc] init];
[userDefaults synchronize];
NSString *status = [defaults stringForKey:#"any status"];
}
Local notification
- (BOOL)application:(UIApplication *)application handleopenURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
{
UILocalNotification *localNotif = [[UILocalNotification alloc] init];
if (localNotif == nil)
return;
localNotif.userInfo = [NSDictionary dictionaryWithObjectsAndKeys:VAL, #"value", nil];
[[UIApplication sharedApplication] scheduleLocalNotification:localNotif];
}
If your viewDidLoad is not called perfectly try in viewWillAppear or viewDidAppear method.
For example purpose:
- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url {
NSDictionary *dict = [self parseQueryString:[url query]];
NSLog(#"query dict: %#", dict);
// add dictionary to standardUserDefaults for saving purpose, like
[[NSUserDefaults standardUserDefaults] setObject:dict forKey:#"DicKey"];
[[NSUserDefaults standardUserDefaults] synchronize];
// add code for navigation/present view controller
UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:#"Main"
bundle: nil];
YourViewController *yourController = (YourViewController *)[mainStoryboard
instantiateViewControllerWithIdentifier:#"YourViewControllerID"];
self.window.rootViewController = yourController;
return YES;
}
for retrieve
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
NSMutableDictionary *mutableRetrievedDictionary = [[[NSUserDefaults standardUserDefaults] objectForKey:#"DicKey"] mutableCopy];
// here parse the dictionary and do your work here, when your works is over
// remove the key of standardUserDefaults
[[NSUserDefaults standardUserDefaults] removeObjectForKey:#"DicKey"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
Store the status from other app in NSUserdefaults, when the ViewController of your app launches fetch the status into a NSString from NSUserdefaults and rise it as an alert.
Call the handleopenURL in appdelegate
- (BOOL)application:(UIApplication *)application handleopenURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
{
NSUserDefaults *defaults=[[NSUserDefaults alloc] init];
[defaults synchronize];
NSString *status = [defaults stringForKey:#"status string from other app"];
}
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
I am very new to Swift and IOS. I want to implement the login with twitter account using OAuth in my swift iOS application.
I implemented it but I got
[{“message”:”Could not authenticate you”,”code”:32}]}
error
Yes it is quite heavy to implement OAuth of the twitter to the iOS. In my applications I am using ACAccountStore for authentication with the twitter. For you I can recommend to use this library.
Too Easy
I used framework STTwitter which is very nice. also watch this video Twitter app only Authentication and check STTwitterDemoiOS demo to more clear.
Step 1: Create Twitter app and get Consumer key and Consumer secrete.
Step 2: Download STTwitter Framework and Drag and drop file into your Xcode project.
Step 3: UIWebView/Safari Login
- (IBAction)signInWithTwitterClicked:(id)sender {
//login by website
self.twitter = [STTwitterAPI twitterAPIWithOAuthConsumerKey:CONSUMER_KEY
consumerSecret:CONSUMER_SECRETE];
[_twitter postTokenRequest:^(NSURL *url, NSString *oauthToken) {
NSLog(#"URL: %#", url);
NSLog(#"OauthToken: %#", oauthToken);
// if(1) {
// [[UIApplication sharedApplication] openURL:url];
//} else {
//WebViewVc taken from STTwitterDemoiOS demo.
WebViewVC *webViewVC = [self.storyboard instantiateViewControllerWithIdentifier:#"WebViewVC"];
[self presentViewController:webViewVC animated:YES completion:^{
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[webViewVC.webView loadRequest:request];
}];
// }
} authenticateInsteadOfAuthorize:NO
forceLogin:#(YES)
screenName:nil
oauthCallback:#"myapp://twitter_access_tokens/"
errorBlock:^(NSError *error) {
NSLog(#"-- error: %#", error);
// _loginStatusLabel.text = [error localizedDescription];
}];
}
//Step 4 and Step 5 imp to callback to our application
Step 4: Configured info.plist as shown in image.
Step 5: Handle application Delegate method
- (NSDictionary *)parametersDictionaryFromQueryString:(NSString *)queryString {
NSMutableDictionary *md = [NSMutableDictionary dictionary];
NSArray *queryComponents = [queryString componentsSeparatedByString:#"&"];
for(NSString *s in queryComponents) {
NSArray *pair = [s componentsSeparatedByString:#"="];
if([pair count] != 2) continue;
NSString *key = pair[0];
NSString *value = pair[1];
md[key] = value;
}
return md;
}
- (BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
sourceApplication:(NSString *)sourceApplication
annotation:(id)annotation
{
//Twitter integration
// if ([[url scheme] isEqualToString:#"myapp"] == NO) return NO;
NSDictionary *d = [self parametersDictionaryFromQueryString:[url query]];
NSString *token = d[#"oauth_token"];
NSString *verifier = d[#"oauth_verifier"];
// NSLog(#"Twitter Token=> %#\n Twitter Verifier=>%#",token,verifier);
ViewController *vc = (ViewController *)[[self window] rootViewController];
StartupViewController *startVc=(StartupViewController *)[[vc childViewControllers] objectAtIndex:0];
[startVc setOAuthToken:token oauthVerifier:verifier];
//startVc is my controller where my "Login with twitter" button is there.
//if no Facebook integration then return YES instead if return //[FBAppCall handleOpenURL:url sourceApplication:sourceApplication];
//Facebook Integration
return [FBAppCall handleOpenURL:url sourceApplication:sourceApplication];
}
Step 6: Get User credentials.
-(void)setOAuthToken:(NSString *)token oauthVerifier:(NSString *)verifier {
// in case the user has just authenticated through WebViewVC
[self dismissViewControllerAnimated:YES completion:^{
//Dismiss presented controller.
}];
[_twitter postAccessTokenRequestWithPIN:verifier successBlock:^(NSString *oauthToken, NSString *oauthTokenSecret, NSString *userID, NSString *screenName) {
//Here is your Ans.
NSLog(#"SUCCESS screenName: %# ,userID=%#", screenName,userID);
} errorBlock:^(NSError *error) {
NSLog(#"-- %#", [error localizedDescription]);
}];
}
hope this help some one.
I am using the Facebook SDK for the first time. I am working with Xcode 5.1 and iOS 7.
I programmatically display FBLoginView:
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(#"viewDidLoad");
// Do any additional setup after loading the view.
if ( !loginView ) {
// loginView =[[FBLoginView alloc] initWithReadPermissions:#[#"basic_info"]];
loginView =[[FBLoginView alloc] initWithReadPermissions:[NSArray arrayWithObjects:#"basic_info", #"user_location", nil]];
}
loginView.delegate = self;
loginView.frame = CGRectOffset(loginView.frame,
(self.view.center.x -(loginView.frame.size.width /2)), 5);
CGPoint vCenter = CGPointMake( CGRectGetMidX(self.view.frame),
CGRectGetMidY(self.view.frame) );
CGPoint lvCenter = CGPointMake( vCenter.x, vCenter.y+100.0 );
loginView.center = lvCenter;
[self.view addSubview:loginView];
[self updateView];
}
I have implemented the required override functions:
#pragma mark - FBLoginViewDelegate
- (void) loginViewFetchedUserInfo:(FBLoginView *)loginView user:(id<FBGraphUser>)user {
NSLog(#"loginViewFetchedUserInfo");
[self updateView];
}
- (void) loginViewShowingLoggedInUser:(FBLoginView *)loginView {
NSLog(#"loginViewShowingLoggedInUser");
[self updateView];
}
- (void) loginViewShowingLoggedOutUser:(FBLoginView *)loginView {
NSLog(#"loginViewShowingLoggedOutUser");
[self updateView];
}
- (void)updateView {
NSLog(#"FB updateView");
[[FBRequest requestForMe] startWithCompletionHandler:
^(FBRequestConnection *connection, NSDictionary<FBGraphUser>*FBUser, NSError *error) {
if (error) {
NSLog(#"updateView - error");
} else {
NSLog(#"updateView - good");
NSNumber *owner_id = [NSNumber numberWithLong:[[FBUser id] longLongValue]];
if ( FB_user_id == nil ) {
FB_user_id = owner_id;
NSLog(#"FBUser ID = %#", FB_user_id);
loggedInSession = [FBSession activeSession];
[[NSUserDefaults standardUserDefaults] setObject:[FBUser id] forKey:#"eventOwnerID"];
[self performSegueWithIdentifier:#"continue_to_app" sender:self];
}
}
}];
if ([self checkFacebookSession]) {
}
dispatch_async(dispatch_get_main_queue(), ^{
[self.view setNeedsDisplay];
});
}
The FBLoginView button appears with "Log in with Facebook". I can log in and accept permissions, but the loginViewShowingLoggedInUser override function never gets called.
Someone suggested adding the following:
- (BOOL) application:(UIApplication *) application
openURL:(NSURL *)url
sourceApplication:(NSString *)sourceApplication
annotation:(id)annotation
{
NSLog ( #"application openURL");
NSLog ( #"URL = %#", url);
NSLog ( #"Application = %#", sourceApplication);
// Call FBAppCall's ha
BOOL wasHandled = [FBAppCall handleOpenURL:url sourceApplication:sourceApplication];
//[LoginUIViewController updateView];
return wasHandled;
}
This code had no effect and was never executed.
What am I doing wrong?
You are using #"basic_info", for this Facebook shows following error when I tried testing your code!
Invalid Scope: basic_info. Use public_profile, user_friends instead
I was interested in knowing where did you add the method:
- (BOOL) application:(UIApplication *) application
openURL:(NSURL *)url
sourceApplication:(NSString *)sourceApplication
annotation:(id)annotation
{
NSLog ( #"application openURL");
NSLog ( #"URL = %#", url);
NSLog ( #"Application = %#", sourceApplication);
// Call FBAppCall's ha
BOOL wasHandled = [FBAppCall handleOpenURL:url sourceApplication:sourceApplication];
//[LoginUIViewController updateView];
return wasHandled;
}
It should be in your AppDelegate, which works for me.
The read permissions have changed.
Refer this :
[https://developers.facebook.com/docs/apps/changelog#v2_0_permissions
][1]
The Error "invalide scope : basic info use public_profile, user friends instead" clearly states that "basic_info" is invalid and it suggests to make use of "public_profile" or "user_friends" as the new scope.
Change it in the following code:
self.loginView.readPermissions = #[#"basic_info"];
TO
self.loginView.readPermissions = #[#"public_profile"];
I'm creating an app that uses a custom url scheme, I have it all set up and it works when opening the app up, however, I now want to be able to add a single string to the url so that the person that opens the app can see that string. I'm really struggling with this, can someone help me please?
Here is my code
- (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 objectAtIndex:1]
stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
[params setObject:val forKey:[kv objectAtIndex:0]];
}
return params;
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
NSString *title = [alertView buttonTitleAtIndex:buttonIndex];
if([title isEqualToString:#"Send Challenge"])
{
[FBWebDialogs presentRequestsDialogModallyWithSession:nil
message:[NSString stringWithFormat:#"I just scored %i points on this great game, called SumsUp. can you beat it?!", gameScore]
title:nil
parameters:nil
handler:^(FBWebDialogResult result, NSURL *resultURL, NSError *error) {
if (error)
{
// Error launching the dialog or sending the request.
NSLog(#"Error sending request.");
}
else
{
if (result == FBWebDialogResultDialogNotCompleted)
{
// User clicked the "x" icon
NSLog(#"User canceled request.");
}
else
{
// Handle the send request callback
NSDictionary *urlParams = [self parseURLParams:[resultURL query]];
if (![urlParams valueForKey:#"request"])
{
// User clicked the Cancel button
NSLog(#"User canceled request.");
}
else
{
// User clicked the Send button
NSString *requestID = [urlParams valueForKey:#"request"];
NSLog(#"Request ID: %#", requestID);
}
}
}
}];
}
I have got the custom url setup in the P-List.
in my app delegate I have:
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
{
UIAlertView *alertView;
NSString *text = [NSString stringWithFormat: #"url recieved: %#", url];
alertView = [[UIAlertView alloc] initWithTitle:#"" message:text delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alertView show];
return [FBAppCall handleOpenURL:url sourceApplication:sourceApplication withSession:[PFFacebookUtils session]];
}
I hope this makes sense and somebody can help me. If any more information is required please let me know?
Thanks Graham
I had problem with custom URL Scheme on ios v. 9.x.x. when i tried open Youtube URL by App. I have found interesting fact when i have browsed through network.
iOS 9 requires your app to pre-register application schemes it intends to call.
Open your YourApp-Info.plist file and add the key, LSApplicationQueriesSchemes.
List item under LSApplicationQueriesSchemes, add a
new item with the value youtube (in my case).
<key>LSApplicationQueriesSchemes</key>
<array>
<string>youtube</string>
</array>
My solution is simpler. I hope you will find it useful.
- (BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
sourceApplication:(NSString *)sourceApplication
annotation:(id)annotation
{
// Example URL: myapp://myapp.com/showString/yourString
BOOL isMyAppURL = [[url scheme] isEqualToString:#"myapp"];
if (isMyAppURL)
{
NSArray* pathComponents = [url pathComponents];
NSString *command = pathComponents[0];
// Check for showString command.
if ([command isEqualToString:#"showString"])
{
NSString *stringToShow = [pathComponents[1] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSLog(#"String to show: %#", stringToShow);
}
}
return isMyAppURL;
}
This should point you to the right direction.
I am trying to integrate Facebook connect to my iPhone app but I have an error (code 10000):
did fail: The operation couldn’t be completed. (facebookErrDomain error 10000.)
When I try to update my wall. The code seems pretty simple (I had to struggle to find some doc though).
- (void)viewDidLoad {
[super viewDidLoad];
// Permissions
NSArray *permissions = [[NSArray arrayWithObjects:#"publish_stream",#"read_stream",#"offline_access",nil] retain];
// Connection
Facebook *facebook = [[Facebook alloc] init];
[facebook authorize:#"MY_APP_ID" permissions:permissions delegate:self];
// Update my wall
NSMutableDictionary * params = [NSMutableDictionary dictionaryWithObjectsAndKeys:#"MY_API_KEY", #"api_key", #"test", #"message", nil];
[facebook requestWithGraphPath:#"me/home" andParams:params andHttpMethod:#"POST" andDelegate:self];
}
// FBRequestDelegate
- (void)request:(FBRequest*)request didLoad:(id)result {
NSArray* users = result;
NSDictionary* user = [users objectAtIndex:0];
NSString* name = [user objectForKey:#"name"];
NSLog(#"Query returned %#", name);
}
- (void)request:(FBRequest*)request didFailWithError:(NSError*)error {
NSLog(#"did fail: %#", [error localizedDescription]);
}
- (void)request:(FBRequest*)request didReceiveResponse:(NSURLResponse*)response {
NSLog(#"did r response");
}
Cannot really figure out what is wrong.
Thanks a lot,
Luc
I think I figured it out, I used to have the same issue. Your issue should be solved if you authenticate first with the right permissions and make sure you actually get to accept the needed permissions (publish_stream). Make sure you actually get to press the "allow" button. In your current code you won't see it, because you immediately try to post a message after authenticating, yet authentication isn't yet completed. As a result you most likely don't have a valid accessToken, preventing you to post messages to the wall.
// you perform authorization, but you don't wait for the user to accept the publish permission
[facebook authorize:#"MY_APP_ID" permissions:permissions delegate:self];
// you attempt to publish, but you don't have the permission to publish yet ...
NSMutableDictionary * params = [NSMutableDictionary dictionaryWithObjectsAndKeys:#"MY_API_KEY", #"api_key", #"test", #"message", nil];
[facebook requestWithGraphPath:#"me/home" andParams:params andHttpMethod:#"POST" andDelegate:self];
How to fix this issue?
This is the way I fixed it (please note DLog() is a macro for NSLog()):
/* The operationQueue array is used to keep track of operations that need to be
completed in order (e.g. if we aren't logged in when we want to post, first
log in, then post - this way we'll make sure we always have a valid
accessToken. */
- (id)initWithDelegate:(id <ServiceDelegate>)serviceDelegate
{
self = [super init];
if (self)
{
[self setDelegate:serviceDelegate];
userId = nil;
operationQueue = [[NSMutableArray alloc] init];
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
facebook = appDelegate.facebook;
}
return self;
}
- (id)init
{
return [self initWithDelegate:nil];
}
- (void)dealloc
{
[operationQueue release];
[super dealloc];
}
#pragma mark - Instance methods
- (void)login
{
if (![facebook isSessionValid]) {
SEL authorizationSelector = #selector(performAuthorization);
NSValue *selector = [NSValue valueWithPointer:authorizationSelector];
NSDictionary *dictionary = [NSDictionary dictionaryWithObject:selector forKey:#"selector"];
[operationQueue addObject:dictionary];
[self runOperations];
}
}
- (void)logout
{
SEL logoutSelector = #selector(performLogout);
NSValue *selector = [NSValue valueWithPointer:logoutSelector];
NSDictionary *dictionary = [NSDictionary dictionaryWithObject:selector forKey:#"selector"];
[operationQueue addObject:dictionary];
[self runOperations];
}
- (void)postMessage:(NSString *)message
{
NSArray *objects = [NSArray arrayWithObjects:message, nil];
NSArray *keys = [NSArray arrayWithObjects:#"message", nil];
NSMutableDictionary *parameters = [NSMutableDictionary dictionaryWithObjects:objects forKeys:keys];
NSDictionary *dictionary = [NSDictionary dictionaryWithObject:parameters forKey:#"parameters"];
SEL postMessageSelector = #selector(performPostMessageWithDictionary:);
NSValue *selector = [NSValue valueWithPointer:postMessageSelector];
NSDictionary *operationDictionary = [NSDictionary dictionaryWithObjectsAndKeys:selector, #"selector", dictionary, #"parameters", nil];
[operationQueue addObject:operationDictionary];
if (![facebook isSessionValid]) {
[self performSelectorOnMainThread:#selector(performAuthorization) withObject:nil waitUntilDone:NO];
} else {
[self runOperations];
}
}
#pragma mark - Private methods
- (void)runOperations
{
DLog(#"running operations ...");
for (NSDictionary *operationDictionary in operationQueue) {
NSValue *value = [operationDictionary objectForKey:#"selector"];
SEL selector = [value pointerValue];
NSDictionary *parameters = [operationDictionary objectForKey:#"parameters"];
[self performSelectorOnMainThread:selector withObject:parameters waitUntilDone:YES];
}
[operationQueue removeAllObjects];
}
- (void)performLogout {
[facebook logout:self];
}
- (void)performAuthorization {
NSArray *permissions = [NSArray arrayWithObject:#"publish_stream"];
[facebook authorize:permissions delegate:self];
}
- (void)performPostMessageWithDictionary:(NSDictionary *)dictionary {
NSMutableDictionary *parameters = [dictionary objectForKey:#"parameters"];
NSString *encodedToken = [facebook.accessToken stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSString *graphPath = [NSString stringWithFormat:#"me/feed?access_token=%#", encodedToken];
FBRequest *request = [facebook requestWithGraphPath:graphPath
andParams:parameters
andHttpMethod:#"POST"
andDelegate:self];
if (!request) {
DLog(#"error occured when trying to create FBRequest object with graph path : %#", graphPath);
}
}
/* make sure your interface conforms to the FBRequestDelegate protocol for
extra debug information, but this is not required */
#pragma mark - Facebook request delegate
- (void)requestLoading:(FBRequest *)request
{
DLog(#"requestLoading:");
}
- (void)request:(FBRequest *)request didReceiveResponse:(NSURLResponse *)response
{
DLog(#"request:didReceiveResponse:");
}
- (void)request:(FBRequest *)request didFailWithError:(NSError *)error
{
DLog(#"error occured when trying to perform request to Facebook : %#", error);
}
- (void)request:(FBRequest *)request didLoad:(id)result
{
DLog(#"request:didLoad: %#", result);
}
- (void)request:(FBRequest *)request didLoadRawResponse:(NSData *)data
{
DLog(#"request:didLoadRawResponse");
}
/* make sure your interface conforms to the FBSessionDelegate protocol! */
#pragma mark - Facebook session delegate
/* if there are still operations in the queue that need to be completed,
continue executing the operations, otherwise inform out delegate that login
is completed ... */
- (void)fbDidLogin
{
if ([operationQueue count] > 0) {
[self runOperations];
}
if ([self.delegate respondsToSelector:#selector(serviceDidLogin:)])
{
[self.delegate serviceDidLogin:self];
}
}
- (void)fbDidNotLogin:(BOOL)cancelled
{
if ([self.delegate respondsToSelector:#selector(serviceLoginFailed:)])
{
[self.delegate serviceLoginFailed:self];
}
}
- (void)fbDidLogout
{
if ([self.delegate respondsToSelector:#selector(serviceDidLogout:)])
{
[self.delegate serviceDidLogout:self];
}
}
Make sure you have declared your app's API key.