Give iOS app permanent permission to post to Facebook - ios

I have integrated Facebook sharing using SLRequest into my iOS app. Everything works fine, but everytime I want to post, the user is shown a hint asking whether the app should be allowed to post on his behalf.
For some reasons (I'm posting from an Apple Watch), it would be important to get permanent permission to post. Otherwise it would be a very bad user experience.
So I'm looking after a possibility to permanently enable posting on the users behalf for my app.
- (void)postToFacebook:(NSString *)postMessage toAudience:(int)audienceIndex {
ACAccountStore *accountStore = [[ACAccountStore alloc] init];
ACAccountType *accountTypeFacebook =
[accountStore accountTypeWithAccountTypeIdentifier:
ACAccountTypeIdentifierFacebook];
NSArray *audienceArray = [[NSArray alloc] initWithObjects:#"ACFacebookAudienceEveryone", #"ACFacebookAudienceFriends", #"ACFacebookAudienceOnlyMe", nil];
NSDictionary *options = #{ACFacebookAppIdKey: #"<HERE'S MY FACEBOOK APP ID>", ACFacebookPermissionsKey: #[#"publish_actions"], ACFacebookAudienceKey: [audienceArray objectAtIndex:audienceIndex]};
[accountStore requestAccessToAccountsWithType:accountTypeFacebook options:options completion:^(BOOL granted, NSError *error) {
if(granted) {
NSArray *accounts = [accountStore accountsWithAccountType:accountTypeFacebook];
ACAccount *facebookAccount = [accounts lastObject];
NSDictionary *parameters =
#{#"access_token":facebookAccount.credential.oauthToken,
#"message": postMessage};
NSURL *feedURL = [NSURL URLWithString:#"https://graph.facebook.com/me/feed"];
SLRequest *feedRequest = [SLRequest requestForServiceType:SLServiceTypeFacebook requestMethod:SLRequestMethodPOST URL:feedURL parameters:parameters];
[feedRequest performRequestWithHandler:^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error) {
NSLog(#"Request failed, %#", [urlResponse description]);
}];
} else {
NSLog(#"Access Denied");
NSLog(#"[%#]",[error localizedDescription]);
}
}];
}

Unfortunately, there is no longer the notion of "permanent permission to post to Facebook".
The offline_access permission is deprecated and was removed December 5th, 2012 (originally scheduled for July 5th).
See: Developer Docs > Migration > Remove offline_access Permission
It was replaced by a new 60-day long term access token.
See: Developer Docs > Facebook Login > Access Tokens
Short-Term and Long-Term Tokens
User access tokens come in two forms: short-lived tokens and
long-lived tokens. Short-lived tokens usually have a lifetime of about
an hour or two, while long-lived tokens usually have a lifetime of
about 60 days. You should not depend on these lifetimes remaining the
same - the lifetime may change without warning or expire early. See
more under handling errors.
Access tokens generated via web login are short-lived tokens, but you
can upgrade them to long-lived tokens. Converting short-lived tokens
to long-lived tokens is covered later in this document under
Expiration and Extending Tokens.
Mobile apps that use Facebook's mobile SDKs get long-lived tokens.
Essentially, mobile applications using newer SDKs will automatically be granted a user access_token with the longer expiration. So long as a user revisits your app within 60 days, you will be granted a new user access_token with a fresh expiration time. If your users wait longer than 60 days, they will have to log in again.

Related

Save Facebook account using ACAccountStore

I'm trying to use iOS Social.framework to share to Facebook. However, most users will not have Facebook setup in Settings>Facebook so therefore Facebook doesn't show up when you bring up a UIActivityViewController, it just isn't listed. (See UIActivity with no settings for Facebook or just google "facebook doesn't show in UIActivityViewController," there's plenty of people trying to solve this problem.)
Our app already uses the Facebook SDK so I can get at the Facebook account info, so I thought I would just get the info and then save the info in Settings>Facebook. Here's my code. (Which I got from When do we use saveAccount:(ACAccount *)account of ACAccountStore class? and iOS requestAccessToAccountsWithType is Not Showing Permission Prompt / NSAlert)
- (void)storeAccountWithAccessToken:(NSString *)token secret:(NSString *)secret {
if (self.accountStore == nil) {
self.accountStore = [[ACAccountStore alloc] init];
}
//We start creating an account by creating the credentials object
ACAccountCredential *credential = [[ACAccountCredential alloc] initWithOAuthToken:token tokenSecret:secret];
ACAccountType *acctType =[self.accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierFacebook];
ACAccount *newAccount = [[ACAccount alloc] initWithAccountType:acctType];
//Here we assign credentials and now can save account
newAccount.credential = credential;
NSDictionary *options = [[NSDictionary alloc] initWithObjectsAndKeys:
[VVEnvironment stringForKey:kVVEnvironmentKeyFacebookAppID], (NSString *)ACFacebookAppIdKey,
[NSArray arrayWithObject:#"basic_info"], (NSString *)ACFacebookPermissionsKey,
ACFacebookAudienceEveryone, (NSString *)ACFacebookAudienceKey,
nil];
[_accountStore requestAccessToAccountsWithType:acctType options:options completion:^(BOOL granted, NSError *error) {
if (granted == YES) {
[self.accountStore saveAccount:newAccount withCompletionHandler:^(BOOL success, NSError *error) {
if (success) {
NSLog(#"the account was saved!");
}
else {
if ([error code] == ACErrorPermissionDenied) {
NSLog(#"Got a ACErrorPermissionDenied, the account was not saved!");
}
NSLog(#"the account was not saved! %d, %#", [error code], error);
}
}];
}
else {
NSLog(#"ERR: %# ",error);
}
}];
}
I added the call to requestAccessToAccountsWithType there because without I was getting a ACErrorPermissionDenied back from saveAccount. When I run this I do see my app slide briefly aside for the Facebook dialog (if I delete my app on Facebook's website it does bring up the full dialog asking me for permissions which I grant.)
The problem is that granted is always NO, so I never get a chance to save the account. What am I missing here?
I am running this on a real device that has the Facebook App installed and setup.
I'd appreciate any help on this, thanks!
There is no solution available for this. iOS native facebook applications are not allowed to write or save account to ACAccountStore. It only allow to access account from the ACAccountStore. iOS only allow to store 1 facebook account at a time. Try to do these steps you will understand this easily,
Add a facebook account to settings App and try to get permission to access it. It will grand permission.
Remove account and try to get the permission it will deny access.
Add a facebook account and get access and try to save new account to ACAccountStore, It will say that Native applications are not allowed to save account to ACAccountStore.
The proposed solution is, Add the account to settings App and login with it and Share using Social framework or presentOSIntegratedDialog.

How do I get the oauth token after logging into Twitter?

After logging into Twitter, I am able to print out some useful data such as the username and user ID. However, the OAuth token is always null. How do I get it? I need to send OAuth token to my server so it can verify that the user is indeed who he says he is.
ACAccountStore* accountStore = [[ACAccountStore alloc] init];
ACAccountType* twitterType = [self.context.accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierTwitter];
[accountStore
requestAccessToAccountsWithType:twitterType
withCompletionHandler:^(BOOL isAllowed, NSError* error) {
dispatch_sync(dispatch_get_main_queue(), ^(void) {
if (isAllowed) {
ACAccount* account = [[self.context.accountStore accountsWithAccountType:[self.context.accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierTwitter]] lastObject];
NSLog(#"username = %#", account.username);
NSLog(#"user_id = %#", [[account valueForKey:#"properties"] valueForKey:#"user_id"]);
// ouath token is always null
NSLog(#"oauth token = %#", account.credential.oauthToken);
}
});
}
];
I "think" I need Reverse Auth, but that tutorial mysteriously left out the code for "step 1".
You will indeed need to use Reverse Auth.
I recently used Sean Cook's TWReverseAuth and it worked very well. Just be careful to turn off ARC for the individual files in the Vendor directory.

Sending Tweet without TWTweetComposeViewController

I want to send a tweet directly from my iPhone app without showing TWTweetComposeViewController pop up
Also i want to get all followers
is there a way to do it from twitter framework on the ios5 or should i use another api!
If I have to use another api can u specify a great api for me ? because all the apis i found
on the internet was so old.
Thanks in advance
You can use TWRequest for programatically posting tweets from my app, if you are using iOS 5.0 and up. Posting tweets is quite straightforward and there is no need for an external framework or anything.
You need the #import <Twitter/Twitter.h>. You retrieve the twitter account from the iPhone account store (you could check if there are multiple accounts) and then you use the account to post the request.
Here is an example of a method for posting a tweet with an image.
- (void)shareTwitterImage:(UIImage *)image
{
ACAccountStore *accountStore = [[ACAccountStore alloc] init];
ACAccountType *accountType = [accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierTwitter];
[accountStore requestAccessToAccountsWithType:accountType withCompletionHandler:^(BOOL granted, NSError *error)
{
if(granted)
{
NSArray *accountsArray = [accountStore accountsWithAccountType:accountType];
if ([accountsArray count] > 0)
{
ACAccount *twitterAccount = [accountsArray objectAtIndex:0];
TWRequest *postRequest = [[TWRequest alloc] initWithURL:[NSURL URLWithString:#"https://upload.twitter.com/1/statuses/update_with_media.json"] parameters:[NSDictionary dictionaryWithObject:self.textViewOutlet.text forKey:#"status"] requestMethod:TWRequestMethodPOST];
[postRequest addMultiPartData:UIImagePNGRepresentation(image) withName:#"media" type:#"multipart/png"];
[postRequest setAccount:twitterAccount];
[postRequest performRequestWithHandler:^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error)
{
//show status after done
NSString *output = [NSString stringWithFormat:#"HTTP response status: %i", [urlResponse statusCode]];
NSLog(#"Twiter post status : %#", output);
}];
}
}
}];
}
There are quite a few options:
Well, on iOS 6, there is the Apple Social framework, and you can use SLComposeViewController to post to Twitter as well as Facebook and Sina Weibo, here are the docs. TWTweetComposeViewController has been deprecated, devices running iOS 6 will have to run into backward compatibility -- so avoid that.
There is also ShareKit, however I do not generally recommend it, its messy and bloated. Lastly there is the Oauth Library in iOS... create a consumer key and secret key. You can also call the Twitter API with TWRequest.
That's all of them I can think of.
Rohan.
In case you plan on integrating TwitterKit by Twitter to perform the tweets via your custom twitter app then this might help you.
https://stackoverflow.com/a/28602749/1740354
With the same methods you can get the followers list by using the following API
https://dev.twitter.com/rest/reference/get/followers/list
Hope it helps.

When do we use saveAccount:(ACAccount *)account of ACAccountStore class?

Please clarify me when do we use this method ?
- (void)saveAccount:(ACAccount *)account withCompletionHandler:(ACAccountStoreSaveCompletionHandler)completionHandler
As I know we get access to the account through OAuth and we do not get user's credentials. So how do we create an account? I've found that ACAccount has the only one creation method:
- (id)initWithAccountType:(ACAccountType *)type
What actually happens when we create account this way? And can we save it now ?
Ok, finally I've found the information about it.
Consider this scenario:
Our app have already been authorized by the user and we've got both access token and secret. Now we want to support new iOS 6 features and create twitter (for example) account in Settings. To do this we need to migrate these tokens to the central account store.
Here's how:
- (void)storeAccountWithAccessToken:(NSString *)token secret:(NSString *)secret {
//We start creating an account by creating the credentials object
ACAccountCredential *credential = [[ACAccountCredential alloc] initWithOAuthToken:token tokenSecret:secret];
ACAccountType *twitterAcctType =[self.accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierTwitter];
ACAccount *newAccount = [[ACAccount alloc] initWithAccountType:twitterAcctType];
//Here we assign credentials and now can save account
newAccount.credential = credential;
[self.accountStore saveAccount:newAccount withCompletionHandler:^(BOOL success, NSError *error) {
if (success) {
NSLog(#"the account was saved!");
}
else {
//Handle error here
}
}];
}
For more information about it read here how to migrate tokens

Using a Hidden Twitter Account

Not sure if any one has tried this. I want to access twitter with an account that the user of the phone doesn't have access to.
The way I have looked at it is by adding a twitter account using the OAth (token/secret)
I can add an account using the following code.
NSString *token = #"blahblahblah";
NSString *secret = #"blahblahblah";
ACAccountStore *store = [[ACAccountStore alloc] init];
ACAccountCredential *credential = [[ACAccountCredential alloc] initWithOAuthToken:token tokenSecret:secret];
ACAccountType *twitterAcctType = [store accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierTwitter];
ACAccount *newAccount = [[ACAccount alloc] initWithAccountType:twitterAcctType];
newAccount.credential = credential;
[store saveAccount:<#(ACAccount *)#> withCompletionHandler:<#^(BOOL success, NSError *error)completionHandler#>
[store saveAccount:newAccount withCompletionHandler:^(BOOL success, NSError *error) {
if (success) {
NSLog(#"Account was saved!");
} else {
//something went wrong, check value of error
}
}];
But this code stores the user id associataed with the secret in the iphones account store. The problem being that if the phone user then uses twitter the account privilages are still there for him to use...
There doesn't seem to be a store deleteAccount method implemented
For my second attempt i tried using just the user that was created without adding it to the account store but I think the SaveAccount method is what verifies the token and secret and gets the user name...
Any tips???
Just a friendly reminder that this will most likely have your app banned from the app store, as this can easily be classified as spying on the user/device, if you can pull it off which I doubt.
Also, beware of having thousands/millions of users twitting from the same account.
Finally, there does not seem to be a way to remove the account, as you said, plus in order to use it you'd need to use requestAccessToAccountsWithType:withCompletionHandler: which would trigger a notice to the user and would make them think you were requesting access to his tweeter account, rather than yours...

Resources