我正在努力解决这个问题两天。我正在使用Fabric SDK和Rest工具包,试图为Twitter使用不同的Rest API Web服务。我可以使用TWTRLogInButton
使用authTokenSecret
,authToken
和其他值的会话对象成功登录。当我尝试获取用户时间线时,我总是得到失败的回应:
{"errors":[{"code":215,"message":"Bad Authentication data.
"}]}
完整错误日志是:
E restkit.network:RKObjectRequestOperation.m:297 Object request failed: Underlying HTTP request operation failed with error: Error Domain=org.restkit.RestKit.ErrorDomain Code=-1011 "Expected status code in (200-299), got 400" UserInfo=0x1780f6f80 {NSLocalizedRecoverySuggestion={"errors":[{"code":215,"message":"Bad Authentication data."}]}, NSErrorFailingURLKey=https://api.twitter.com/1.1/statuses/user_timeline.json?user_id=3116882322&count=2&screen_name=ann_10p, AFNetworkingOperationFailingURLRequestErrorKey=<NSMutableURLRequest: 0x178202740> { URL: https://api.twitter.com/1.1/statuses/user_timeline.json?user_id=3116882322&count=2&screen_name=ann_10p }, AFNetworkingOperationFailingURLResponseErrorKey=<NSHTTPURLResponse: 0x1702271e0> { URL: https://api.twitter.com/1.1/statuses/user_timeline.json?user_id=3116882322&count=2&screen_name=ann_10p } { status code: 400, headers {
"Content-Encoding" = gzip;
"Content-Length" = 87;
"Content-Type" = "application/json;charset=utf-8";
Date = "Wed, 01 Apr 2015 09:46:42 GMT";
Server = "tsa_a";
"Strict-Transport-Security" = "max-age=631138519";
"x-connection-hash" = 4c123a59a023cd86b2e9a3e9fc84cd7b;
"x-response-time" = 4;
} }, NSLocalizedDescription=Expected status code in (200-299), got 400}
2015-04-01 14:47:13.223 TwitterIntegration[1086:60b] I restkit.network:RKHTTPRequestOperation.m:154 GET 'https://api.twitter.com/1.1/statuses/user_timeline.json?user_id=3116882322&count=2&screen_name=ann_10p'
2015-04-01 14:47:13.225 TwitterIntegration[1086:60b] E restkit.network:RKHTTPRequestOperation.m:178 GET 'https://api.twitter.com/1.1/statuses/user_timeline.json?user_id=3116882322&count=2&screen_name=ann_10p' (400 Bad Request) [0.0013 s]: Error Domain=org.restkit.RestKit.ErrorDomain Code=-1011 "Expected status code in (200-299), got 400" UserInfo=0x1780f6f80 {NSLocalizedRecoverySuggestion={"errors":[{"code":215,"message":"Bad Authentication data."}]}, NSErrorFailingURLKey=https://api.twitter.com/1.1/statuses/user_timeline.json?user_id=3116882322&count=2&screen_name=ann_10p, AFNetworkingOperationFailingURLRequestErrorKey=<NSMutableURLRequest: 0x178202740> { URL: https://api.twitter.com/1.1/statuses/user_timeline.json?user_id=3116882322&count=2&screen_name=ann_10p }, AFNetworkingOperationFailingURLResponseErrorKey=<NSHTTPURLResponse: 0x1702271e0> { URL: https://api.twitter.com/1.1/statuses/user_timeline.json?user_id=3116882322&count=2&screen_name=ann_10p } { status code: 400, headers {
"Content-Encoding" = gzip;
"Content-Length" = 87;
"Content-Type" = "application/json;charset=utf-8";
Date = "Wed, 01 Apr 2015 09:46:42 GMT";
Server = "tsa_a";
"Strict-Transport-Security" = "max-age=631138519";
"x-connection-hash" = 4c123a59a023cd86b2e9a3e9fc84cd7b;
"x-response-time" = 4;
} }, NSLocalizedDescription=Expected status code in (200-299), got 400}
代码:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self addLoginButton];
}
-(void) addLoginButton
{
TWTRLogInButton *logInButton = [TWTRLogInButton buttonWithLogInCompletion:^(TWTRSession *session, NSError *error) {
// play with Twitter session
if(session)
{
NSLog(@"logged in success! with session : %@", session);
[Global sharedInstance].session = session;
[self requestUserTimeline];
}
else
{
NSLog(@"session is null");
}
}];
logInButton.center = self.view.center;
[self.view addSubview:logInButton];
}
-(void) requestUserTimeline
{
RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[UserTimeline class]];
[mapping addAttributeMappingsFromDictionary:@{
@"text": @"tweetText",
@"favorited": @"favourited",
@"created_at": @"createdAt",
@"user.name": @"name",
@"id": @"tweetID",
@"user.profile_image_url": @"profileImageURL"
}];
NSIndexSet *statusCodes = RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful); // Anything in 2xx
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:mapping pathPattern:nil keyPath:nil statusCodes:statusCodes];
NSString *params = [NSString stringWithFormat:@"?user_id=3116882322&count=2&screen_name=ann_10p",[Global sharedInstance].session.userID,[Global sharedInstance].session.userName];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:[@"https://api.twitter.com/1.1/statuses/user_timeline.json" stringByAppendingString:params]]];
[request setHTTPMethod:@"GET"];
RKObjectRequestOperation *operation = [[RKObjectRequestOperation alloc] initWithRequest:request responseDescriptors:@[responseDescriptor]];
[operation setCompletionBlockWithSuccess:^(RKObjectRequestOperation *operation, RKMappingResult *result) {
UserTimeline *timeline = [result firstObject];
NSLog(@"Mapped the article: %@", timeline);
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
NSLog(@"Failed with error: %@", [error localizedDescription]);
}];
[operation start];
}
请帮我调试这个问题。感谢。
答案 0 :(得分:9)
在尝试使用Fabric SDK之后,我成功地进行了集成。我得出了一些结论,并希望与你们分享。
1)当您第一次成功登录Twitter时,已为用户创建了TWTRSession
的会话。即使您关闭应用程序并重新打开它,它也会持续。
2)如果已经为您创建了会话,并且您尝试登录获取另一个会话对象而未注销,则将返回身份验证错误。
3)您可以使用以下方式检查会话是否存在:
if([[Twitter sharedInstance] session])
{
NSLog(@"session already present!!!");
NSLog(@"signed in as %@", [[[Twitter sharedInstance] session] userName]);
}
else
{
NSLog(@"you need to login!!");
}
4)我建议使用
登录 [[Twitter sharedInstance] logInWithCompletion:^(TWTRSession *session, NSError *error)];
而不是:
[TWTRLogInButton buttonWithLogInCompletion:^(TWTRSession *session, NSError *error)];
当您确定没有会话时,仅使用Twitter的登录按钮 目前存在。
5)如果Twitter的身份验证真的让你感到高兴,请卸载该应用并尝试全新安装。 这是最后一个解决方案!
6)要从会话退出,请使用[[Twitter sharedInstance] logOut];
编码部分:
我假设您已经按照Fabric mac app执行了所有步骤。
首先登录用户,然后提出时间表请求。
-(void) loginUserToTwitter
{
if([[Twitter sharedInstance] session])
{
NSLog(@"session already present!!!");
NSLog(@"signed in as %@", [[[Twitter sharedInstance] session] userName]);
[self getUserTimeline];
}
else
{
NSLog(@"session not found. Make new request!");
[[Twitter sharedInstance] logInWithCompletion:^(TWTRSession *session, NSError *error) {
if(error)
NSLog(@"error occurred... %@",error.localizedDescription);
else
{
NSLog(@"Successfully logged in with session :%@",session);
[self getUserTimeline];
}
}];
}
}
-(void) getUserTimeline
{
NSURLRequest *request = [[[Twitter sharedInstance] APIClient] URLRequestWithMethod:@"GET" URL:@"https://api.twitter.com/1.1/statuses/user_timeline.json"
parameters:@{@"userid": [Twitter sharedInstance].session.userID,
@"count" : @"5",
@"screen_name" : [Twitter sharedInstance].session.userName} error:nil];
NSURLResponse *response;
NSError *error;
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
if(!data)
{
NSLog(@"error....: %@",error.localizedDescription);
}
else
{
NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"%@",string);
[twitterResponse removeAllObjects];
NSArray *arrayRep = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:nil];
twitterResponse = [NSMutableArray arrayWithArray:[TWTRTweet tweetsWithJSONArray:arrayRep]];
[_tableView reloadData];
}
}
我更喜欢Twitter SDK的方法,使用[TWTRTweet tweetsWithJSONArray:arrayRep]
代替Restkit
来提取推文。这里的事情真的很容易处理。
在Twitter的标准风格中显示推文:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
// Setup tableview
self.tableView.estimatedRowHeight = 150;
self.tableView.rowHeight = UITableViewAutomaticDimension; // Explicitly set on iOS 8 if using automatic row height calculation
self.tableView.allowsSelection = NO;
[self.tableView registerClass:[TWTRTweetTableViewCell class] forCellReuseIdentifier:@"TweetCell"];
}
#pragma mark - Tableview Methods
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return twitterResponse.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellID = @"TweetCell";
TWTRTweetTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID forIndexPath:indexPath];
TWTRTweet *tweet = twitterResponse[indexPath.row];
[cell configureWithTweet:tweet];
return cell;
}
// Calculate the height of each row. Must to implement
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
TWTRTweet *tweet = twitterResponse[indexPath.row];
return [TWTRTweetTableViewCell heightForTweet:tweet width:CGRectGetWidth(self.view.bounds)];
}
注意:强>
从here下载 Fabric SDK 。您必须输入电子邮件地址。他们会通过电子邮件向您发送一些下载链接,您必须遵循一些步骤。 Fabric Mac App将让您完全配置xcode项目。
希望它有所帮助!
<强>参考文献:强>
答案 1 :(得分:1)
https://github.com/fhsjaagshs/FHSTwitterEngine
尝试使用此FHSTTwitterEngine工作正常
答案 2 :(得分:0)
您可以直接显示用户时间线。无需直接处理登录或其他网络呼叫。这将自动处理Guest Auth
,然后加载初始推文以及在到达UITableView
结束时加载更多推文:
class UserTimelineViewController: TWTRTimelineViewController, TWTRTweetViewDelegate {
convenience init() {
// Set up the User Timeline
let dataSource = TWTRUserTimelineDataSource(screenName: "TomCruise", APIClient: TWTRAPIClient())
// Set the data source (will automatically load Tweets in `viewWillAppear`
self.init(dataSource: dataSource)
// Update the title displayed in the Navigation bar
self.title = "@\(dataSource.screenName)"
}
func tweetView(tweetView: TWTRTweetView, didSelectTweet tweet: TWTRTweet) {
// Log a message when a cell is tapped
print("Selected tweet with ID: \(tweet.tweetID)")
}
}