I'm trying to save a Twitter account into the ACAccountStore.
I'm authenticating the user with MPOauth (this works perfectly, I can authenticate and post a message) and when I receive the access token and the access token secret I proceed to save the account.
First of all, I split the token access for taking only the token itself, not the user ID. After that this is my code
if ([username length] > 0 && [token length] > 0 && [secret length] > 0) {
ACAccountStore *accountStore = [[ACAccountStore alloc] init];
ACAccountType *accountType = [accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierTwitter];
ACAccount *account = [[ACAccount alloc] initWithAccountType:accountType];
ACAccountCredential *credentials = [[ACAccountCredential alloc] initWithOAuthToken:token tokenSecret:secret];
[account setCredential:credentials];
[account setUsername:username];
[accountStore saveAccount:account withCompletionHandler:^(BOOL success, NSError *error) {
if (success) {
NSLog(#"the account was saved!");
} else {
NSLog(#"the account was NOT saved");
}
[accountStore release];
[account release];
[credentials release];
}];
}
But never works, I get this
Error Domain=NSURLErrorDomain Code=-1012 "The operation couldn’t be completed. (NSURLErrorDomain error -1012.)"
I read that this responds to an error authenticating the data against Twitter, thing that is done by iOS5 framework before saving the account.
I've already read this reponse and the post in Twitter.
What is wrong?
if token is OAToken you should replace this
ACAccountCredential *credentials = [[ACAccountCredential alloc] initWithOAuthToken:token tokenSecret:token];
with this
ACAccountCredential *outhCredential = [[ACAccountCredential alloc] initWithOAuthToken:token.key tokenSecret:token.secret];
You should pass key & secret as 1st and 2nd arguments respectively .
Related
I want to save the facebook account to ACAccountStore in iOS,
I will get accessTocken from facebookSDK but how to obtain tocken and secret
How to save it to ACAccountStore
Thanks in Advance.
------ Edit--------
I have an application that uses facebook to login and after with login information need to share photos that he selected.
My use cases are,
If account already in settings app then I can use it for login and share.
User using safari or webview for login then how I can proceed for sharing.
a. facebook SDK says If the user need to use OS integrated share controller then, login method used to authenticate the user must be native iOS 6.0 authentication..
b. If I need to share option that provided by facebook SDK uses facebook App I don't want this option because I want to avoid App switching as much as possible.
How to solve this..
to do it you should have an accesstoken and secret,
if (self.accountStore == nil) {
self.accountStore = [[ACAccountStore alloc] init];
}
//make credentials to assign to ACAccount
ACAccountCredential *credential = [[ACAccountCredential alloc] initWithOAuthToken:accesstoken tokenSecret:secret];
ACAccountType *acctType =[self.accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierFacebook];
ACAccount *newAccount = [[ACAccount alloc] initWithAccountType:acctType];
newAccount.credential = credential;
NSDictionary *options = [[NSDictionary alloc] initWithObjectsAndKeys:
"xXXXXXX", (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(#"%#",error);
}
}];
}
else {
NSLog(#"%# ",error);
}
}];
I am trying to use the built in iOS 5 Twitter framework and the TwitVid SDK to upload a video to twitter.
Steps I am taking:
1) Use TWRequest to get a signed request.
ACAccountStore *accountStore = [[ACAccountStore alloc] init];
[accountStore requestAccessToAccountsWithType:[accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierTwitter] withCompletionHandler:^(BOOL granted, NSError *error) {
if(error) {
[[[UIAlertView alloc] initWithTitle:#"Sorry!" message:[error description] delegate:nil cancelButtonTitle:#"Okay" otherButtonTitles: nil] show];
}
else if (granted) {
NSArray *arrayOfAccounts = [accountStore accountsWithAccountType:[accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierTwitter]];
if ([arrayOfAccounts count] > 0) {
ACAccount *account = [arrayOfAccounts objectAtIndex:0];
NSURL *spURL = [NSURL URLWithString:#"https://api.twitter.com/1/account/verify_credentials.json"];
TWRequest *twRequest = [[TWRequest alloc] initWithURL:spURL parameters:nil requestMethod:TWRequestMethodGET];
[twRequest setAccount:account];
NSURLRequest *signedURLRequest = [twRequest signedURLRequest];
2) Create an instance of TwitVid and fire off an upload request
TwitVid *twitVid = [[TwitVid alloc] initWithSource:#"Test" delegate:self];
[twitVid uploadWithMediaFileAtPath:moviePath offset:0 message:#"Test Message" mediaID:nil playlistID:nil vidResponseParent:nil userTags:nil geoLatitude:nil geoLongitude:nil tags:nil categoryID:nil description:#"upload test" title:#"The title" xVerifyCredentialsAuthorization:[signedURLRequest valueForHTTPHeaderField:#"Authorization"] xAuthServiceProvider:[spURL absoluteString]];
The first time I did this, I got some error back from the appropriate delegate method, and assumed it was a signing issue (I had some bugs in my code there). Now, no matter what I do, I get NOTHING in any of my delegate methods. Its not sending data, no response is received - nothing. I am at a loss of what to do. Any ideas?
Once a user has tweeted something, I need to differentiate which twitter account he used. Lets consider that the user would have 1 or several accounts configured on the phone.
I need tho know this after the tweet is successful, so the proper place would be the callback. I tried to fetch the accounts using ACAccountStore but it provides an array with all the accounts set up on the phone, not a clue about the last account used (not even the order of the array).
Does anyone knows if TWTweetComposeViewController remembers this account and, how to fetch it?
Thanks
My code:
if ([TWTweetComposeViewController canSendTweet])
{
TWTweetComposeViewController *tweetSheet =
[[TWTweetComposeViewController alloc] init];
[tweetSheet setInitialText:#"initial text"];
[tweetSheet addImage:[UIImage imageNamed:image]];
// Callback
tweetSheet.completionHandler = ^(TWTweetComposeViewControllerResult result) {
// if tweet was successful
if(result == TWTweetComposeViewControllerResultDone) {
// Get the accounts
account = [[ACAccountStore alloc] init];
ACAccountType *accountType = [account accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierTwitter];
[account requestAccessToAccountsWithType:accountType withCompletionHandler:^(BOOL granted, NSError *error)
{
// if access granted I populate the array
if (granted == YES) {
NSArray *arrayOfAccounts = [account accountsWithAccountType:accountType];
ACAccount *account1 = [arrayOfAccounts objectAtIndex:0];
ACAccount *account2 = [arrayOfAccounts objectAtIndex:1];
NSString *username1 = account1.username;
NSString *username2 = account2.username;
// Always same order
NSLog(userName1);
NSLog(userName2);
}
}];
[self furtherMethodsInCaseOfSuccessfulTweet];
} else if(result == TWTweetComposeViewControllerResultCancelled) {
NSLog(#"twit canceled");
}
[self dismissViewControllerAnimated:YES completion:nil];
};
[self presentModalViewController:tweetSheet animated:YES];
}
else
{
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"No tweet is possible on this device" delegate:self cancelButtonTitle:#"OK" otherButtonTitles: nil];
[alertView show];
}
}
I found a way.
Instead looking for the username on the insctance of TWTweetComposeViewController , lets use GET users/lookup to qwery the names gathered by ACAccountStore.
http://api.twitter.com/1/users/lookup.xml?screen_name=username1,username2
(use json instead xml)
Parsing the results we can get the date/time of the last tweet of the users ("status" tag), and voila, we have the last account used.
In additiom, you can test the qwery results on the console.
Thanks to #theSeanCook
I'm trying to modify Apple's sample code for using the Twitter API so that I can use the streaming API to filter tweets. I am attempting to implement the method suggested in response to this question:
Does TWRequest work for the twitter streaming api?
I have created the signed NSURLRequest and NSURLConnection objects as suggested, and set the delegate for the connection object. A valid twitter account is selected and used to sign the url. The problem is that the delegates connection:didReceiveData: method is never being called.
Here's my code:
#implementation Twitter
-(id)init{
if (self=[super init]) {
NSLog(#"Twitter init");
// Tell the notification centre to inform the app if the twitter account changes
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(twitterAccountChanged)
name:ACAccountStoreDidChangeNotification object:nil];
// Create an account store object.
ACAccountStore *accountStore = [[ACAccountStore alloc] init];
// Create an account type that ensures Twitter accounts are retrieved.
ACAccountType *accountType = [accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierTwitter];
// Request access from the user to use their Twitter accounts.
[accountStore requestAccessToAccountsWithType:accountType withCompletionHandler:^(BOOL granted, NSError *error) {
if(granted) {
NSLog(#"Twitter: Access to twitter accounts granted");
// Get the list of Twitter accounts.
NSArray *accountsArray = [accountStore accountsWithAccountType:accountType];
// Pick the twitter account to use
if ([accountsArray count] > 0) {
// Grab the initial Twitter account to tweet from.
ACAccount *twitterAccount = [accountsArray objectAtIndex:0];
// This is for a status filter
NSURL *url=[NSURL URLWithString:#"https://stream.twitter.com/1/statuses/filter.json"];
// Create the parameters dictionary
NSDictionary *dictionary=[NSDictionary dictionaryWithObjectsAndKeys:#"twitter", #"track", nil];
// Create TWRequest object
TWRequest *req=[[TWRequest alloc] initWithURL:url parameters:dictionary requestMethod:TWRequestMethodPOST];
// Set the account
[req setAccount:twitterAccount];
// Get a signed URL request
NSURLRequest *signedRequest=[req signedURLRequest];
// Initate the connection
[NSURLConnection connectionWithRequest:signedRequest delegate:self];
} else {
NSLog(#"Twitter: No twitter accounts to access");
}
} else {
NSLog(#"Twitter: Access to twitter accounts denied");
}
}];
return self;
}
return nil;
}
-(void)twitterAccountChanged{
NSLog(#"Twitter twitterAccountChanged");
}
-(void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
NSLog(#"data received");
}
The output from the program is:
2012-07-24 09:50:03.668 TwitterAPITest[36722:10403] Twitter init
2012-07-24 09:50:03.836 TwitterAPITest[36722:11d03] Twitter: Access to twitter accounts granted
As you can see, everything appears to work OK, the only problem is that the delegate method is never called and I currently have no idea why.
Any help would be much appreciated...
Mike
It took me a bit of time to get this up and running, So I thought I aught to post my code for others. In my case I was trying to get tweets close to a certain location, so you will see that I used a locations parameter and a location struct I had in scope. You can add whatever params you want to the params dictionary.
Also note that this is bare bones, and you will want to do things such as notify the user that an account was not found and allow the user to select the twitter account they would like to use if multiple accounts exist.
Happy Streaming!
//First, we need to obtain the account instance for the user's Twitter account
ACAccountStore *store = [[ACAccountStore alloc] init];
ACAccountType *twitterAccountType = [store accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierTwitter];
// Request permission from the user to access the available Twitter accounts
[store requestAccessToAccountsWithType:twitterAccountType
withCompletionHandler:^(BOOL granted, NSError *error) {
if (!granted) {
// The user rejected your request
NSLog(#"User rejected access to the account.");
}
else {
// Grab the available accounts
NSArray *twitterAccounts = [store accountsWithAccountType:twitterAccountType];
if ([twitterAccounts count] > 0) {
// Use the first account for simplicity
ACAccount *account = [twitterAccounts objectAtIndex:0];
NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
[params setObject:#"1" forKey:#"include_entities"];
[params setObject:location forKey:#"locations"];
[params setObject:#"true" forKey:#"stall_warnings"];
//set any other criteria to track
//params setObject:#"words, to, track" forKey#"track"];
// The endpoint that we wish to call
NSURL *url = [NSURL URLWithString:#"https://stream.twitter.com/1.1/statuses/filter.json"];
// Build the request with our parameter
TWRequest *request = [[TWRequest alloc] initWithURL:url
parameters:params
requestMethod:TWRequestMethodPOST];
// Attach the account object to this request
[request setAccount:account];
NSURLRequest *signedReq = request.signedURLRequest;
// make the connection, ensuring that it is made on the main runloop
self.twitterConnection = [[NSURLConnection alloc] initWithRequest:signedReq delegate:self startImmediately: NO];
[self.twitterConnection scheduleInRunLoop:[NSRunLoop mainRunLoop]
forMode:NSDefaultRunLoopMode];
[self.twitterConnection start];
} // if ([twitterAccounts count] > 0)
} // if (granted)
}];
I know that to get access to a configured twitter account using twitter framework in iOS 5, the following can be done:
ACAccountStore *t_account = [[ACAccountStore alloc] init];
ACAccountType *accountType = [account accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierTwitter];
[account requestAccessToAccountsWithType:accountType withCompletionHandler:^(BOOL granted, NSError *error) {
if (granted == YES) {
}
}
But the problem is that I don't have need for a full account, I just want the twitter name if he has configured any on the twitter accounts. So, Is there a way to get just the twitter handle from the framework (not the full account) without asking any user permission ?
You won't get access to any accounts without the user granting permission to access those accounts. Just try through the following in an app delegate in a new project so you know that app has not been given permissions to access the twitter accounts. Of course make sure you have at least one twitter account on the device or in the simulator and the accounts framework imported in your project and app delegate. Also you are making the assumption that the user has only one twitter account. Best to code for a case where a user may have more than one account.
ACAccountStore *accountStore = [[ACAccountStore alloc] init];
// Create an account type that ensures Twitter accounts are retrieved.
ACAccountType *accountType = [accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierTwitter];
NSArray *accountsArray = [accountStore accountsWithAccountType:accountType];
for (ACAccount *account in accountsArray ) {
NSLog(#"Account name: %#", account.username);
}
NSLog(#"Accounts array: %d", accountsArray.count);
Now change the code to return your results when a user has granted permission:
ACAccountStore *accountStore = [[ACAccountStore alloc] init];
// Create an account type that ensures Twitter accounts are retrieved.
ACAccountType *accountType = [accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierTwitter];
[accountStore requestAccessToAccountsWithType:accountType withCompletionHandler:^(BOOL granted, NSError *error) {
if(granted) {
NSArray *accountsArray = [accountStore accountsWithAccountType:accountType];
for (ACAccount *account in accountsArray ) {
NSLog(#"Account name: %#", account.username);
}
NSLog(#"Accounts array: %d", accountsArray.count);
}
}];
So I guess the short answer is, there is a reason apple ask the user to grant permission to user accounts. If that access has not been granted you aren't going to get any data back.