使用Fabric SDK iOS访问Twitter用户时间线

7

我已经为此问题奋斗了两天。我正在使用Fabric SDK和Rest kit,尝试使用不同的Twitter Rest API web服务。我可以成功登录使用TWTRLogInButton并拥有带有authTokenSecretauthToken和其他值的会话对象。但当我尝试获取用户时间轴时,总是返回失败响应,如下所示:

{"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];
}

请帮忙调试这个问题。谢谢。


你在哪里使用认证令牌? - Wain
我该如何在@Wain中使用它?没有关于在任何请求中传递身份验证令牌的文档。但是我在登录后收到了一个。 - NightFury
必须存在,因为您有一个令牌和身份验证失败。身份验证令牌也是标准的。我没有查看文档,但那是您需要寻求指导的地方。 - Wain
3个回答

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 应用程序的所有步骤进行了操作。

首先登录用户,然后发出时间轴请求。

-(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)];

}

注意:

这里下载Fabric SDK。您将需要输入电子邮件地址。他们会给您发送一些下载链接,您需要按照一些步骤进行操作。Fabric Mac App将要求您完全配置xcode项目。

希望能对您有所帮助!

参考文献:

Twitter登录

显示推文

Cannonball示例项目


非常感谢,你的回答太棒了。 - Mariam
我尝试了这个,但是出现了终止应用程序的错误,原因是未捕获的异常 'NSInvalidArgumentException',原因是:'*** -[__NSPlaceholderDictionary initWithObjects:forKeys:count:]:尝试从objects [0]插入nil对象'。 - user717452
@user717452 请检查你的代码。你正在尝试在字典中插入一个空值。 - NightFury

1

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)")
  }

}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接