Think Big Act Local

iPhone開発を軸にブレブレの記事を書いていきます。

iOSアプリでTwitterのタイムライン取得・ツイート投稿を行う(Accounts.frameworkとSocial.rameworkを使って)

iOS 6から Social.framework が登場し、iOSアプリから簡単にツイートできるようになりました。 その方法については以前エントリを書きました。

画像やURLをFacebookやTwitter、LINEなどのSNSに共有する - Think Big Act Local

上記の記事のやり方では、ポップアップを表示→ツイートする ことしかできません。
例えば Twitter のクライアントアプリを作りたい場合、独自のUIでツイートを投稿したり、自分のタイムラインを取得したくなるかと思います。

今回はiOS端末に登録しているTwitterアカウントを使って、自由にTwitter API各種にアクセスする方法を紹介します。

ソースコード全文はこちら

Twitter APIを使ったiOSアプリの作り方

はじめに

  • UIの話はせず、APIコールのロジックの話を書きます
  • Accounts.framework と Social.framework を使います
  • iOS端末に登録しているTwitterアカウントを使う方法です(下図)

f:id:himaratsu:20141102214351p:plain

ここに登録されているTwitterアカウントを使います。

Twitterアカウントの取得

Twitterアカウント取得にAccounts.framework、各種APIのコールにSocial.frameworkを使います。以下のように準備しておきましょう。

import UIKit
import Accounts // 追加
import Social   // 追加

class ViewController: UIViewController {
    
    var accountStore = ACAccountStore()
    var twAccount: ACAccount?

    ...
}

準備ができたら実際にTwitterアカウントを取得します。
以下のメソッドを呼ぶとアカウント認証がリクエストされます。

private func selectTwitterAccount() {
    
    // 認証するアカウントのタイプを選択(他にはFacebookやWeiboなどがある)
    let accountType = accountStore.accountTypeWithAccountTypeIdentifier(ACAccountTypeIdentifierTwitter)
    accountStore.requestAccessToAccountsWithType(accountType, options: nil) { (granted:Bool, error:NSError?) -> Void in
        if error != nil {
            // エラー処理
            println("error! \(error)")
            return
        }
        
        if !granted {
            println("error! Twitterアカウントの利用が許可されていません")
            return
        }
        
        let accounts = self.accountStore.accountsWithAccountType(accountType) as [ACAccount]
        if accounts.count == 0 {
            println("error! 設定画面からアカウントを設定してください")
            return
        }
        
        // 取得したアカウントで処理を行う...

    }
}

初めて認証がリクエストされた際には、以下のアラートが表示されます。

f:id:himaratsu:20141102215713p:plain

ここで拒否されると次回以降は grantedfalse となり、アカウント情報にアクセスできません。うまくエラーメッセージを出すなどして、設定画面よりユーザーに許可してもらう必要があります。

iOS 8以降では設定画面に遷移するURLスキームが使えますので、利用すると良いと思います。

Twitterアカウントを選ぶ

Twitterアカウントは1つの端末に複数アカウント登録できます。
どれか1アカウントだけ利用したい場合は自分で選択させるUIを用意します。

例えば UIAlertController(iOS 7以前ではUIActionSheet)で選択させる場合、コードは以下のようになります。

// アカウント選択のActionSheetを表示する
    private func showAccountSelectSheet(accounts: [ACAccount]) {
        
        let alert = UIAlertController(title: "Twitter",
            message: "アカウントを選択してください",
            preferredStyle: .ActionSheet)
        
        // アカウント選択のActionSheetを表示するボタン
        for account in accounts {
            alert.addAction(UIAlertAction(title: account.username,
                style: .Default,
                handler: { (action) -> Void in
                    //
                    println("your select account is \(account)")
                    self.twAccount = account
            }))
        }
        
        // キャンセルボタン
        alert.addAction(UIAlertAction(title: "Cancel", style: .Cancel, handler: nil))
        
        // 表示する
        self.presentViewController(alert, animated: true, completion: nil)
    }

実行すると以下のように表示されるかと思います。

f:id:himaratsu:20141102222704p:plain

AlertController で選択されたアカウントはtwAccountという変数に保持されます。
以後はこの情報を使ってAPIコールすることになります。

Twitter APIをたたく

タイムラインの取得

Twitterのタイムラインを取得するコードは以下になります。

// タイムラインを取得する
private func getTimeline() {
    let URL = NSURL(string: "https://api.twitter.com/1.1/statuses/user_timeline.json")
    
    // GET/POSTやパラメータに気をつけてリクエスト情報を生成
    let request = SLRequest(forServiceType: SLServiceTypeTwitter,
        requestMethod: .GET,
        URL: URL,
        parameters: nil)
    
    // 認証したアカウントをセット
    request.account = twAccount
    
    // APIコールを実行
    request.performRequestWithHandler { (responseData, urlResponse, error) -> Void in
        
        if error != nil {
            println("error is \(error)")
        }
        else {
            // 結果の表示
            let result = NSJSONSerialization.JSONObjectWithData(responseData,
                options: .AllowFragments,
                error: nil)
                as NSArray
            println("result is \(result)")
        }
    }
}

APIの仕様についてはTwitterAPI リファレンスを見て確認します。
タイムラインの取得だと以下のページになります。

成功すればタイムラインを流れるツイート情報が取得できたかと思います。

新しいツイートの投稿

ツイートを投稿する場合は以下のコードになります。

// ツイートを投稿
private func postTweet() {
    let URL = NSURL(string: "https://api.twitter.com/1.1/statuses/update.json")
    
    // ツイートしたい文章をセット
    let params = ["status" : "Tweet from iOS!"]
    
    // リクエストを生成
    let request = SLRequest(forServiceType: SLServiceTypeTwitter,
        requestMethod: .POST,
        URL: URL,
        parameters: params)
    
    // 取得したアカウントをセット
    request.account = twAccount
    
    // APIコールを実行
    request.performRequestWithHandler { (responseData, urlResponse, error) -> Void in
        
        if error != nil {
            println("error is \(error)")
        }
        else {
            // 結果の表示
            let result = NSJSONSerialization.JSONObjectWithData(responseData, options: .AllowFragments, error: nil) as NSDictionary
            println("result is \(result)")
        }
    }
}

認証したアカウントを確認してみましょう。成功すれば以下のように投稿されていると思います。

無事ツイートできているのが確認できました!

他のAPIをコールするには

他のAPIも上記と同様にコールできます。公式のAPIリファレンスを確認しながら利用しましょう。

日本語だと、以下のようなページもあるようです。

http://dx.24-7.co.jp/twitterapi1-1-rest-api/

http://dx.24-7.co.jp/twitterapi1-1-rest-api/

ソースコード全文

このエントリのソースコードはGistにすべて貼っています。
https://gist.github.com/himaratsu/baaa79c8c2926c472ac1

まとめ

自前でUIを用意できるので、自分のサービスに投稿すると同時にTwitterにポストする場合などに使えますね。
最近Twitter APIを利用するアプリを書く機会が多いのですが、いつも忘れるのでメモでした。

参考リンク

関連書籍