スマートフォン・ジン | Smartphone-Zine

引っ越し先→ https://smartphone-zine.com/

AndroidでTwitterAPIにアクセスしてOAuth認証してホームタイムラインを取得してみる

Twitter APIのパブリックタイムラインはすでに廃止されてしまっています。パブリックタイムラインは認証不要でアクセスできたので学習用に便利だったのですが残念です。 その対策としてソフトバンク・クリエイティブ株式会社の方でダミーURLを用意していただいています。 http://www.sbcr.jp/support/10882.html でも折角なので、ここはちゃんと認証を行なって、タイムラインを取得出来るようにしてみたいと思います。 そのまえに基礎知識。まずはTwitterのホームタイムラインの形式を確認してみましょう。ホームタイムラインとはTwitterで自分がフォローしているユーザーのツイートを一覧表示したものです。ホームタイムラインは次のURLにアクセスしてJSON形式で取得することができます。 https://api.twitter.com/1.1/statuses/home_timeline.json タイムラインのJSONデータ構成(主な要素のみ)

<statuses type="array">
[
    {
        "created_at": "投稿日時",
        "text": "ツイート本文",
        "user": {
            "screen_name": "ユーザー名",
            "followers_count": フォロワーの数,
            "friends_count": フォローしている数,
            "statuses_count": 総ツイート件数,
            "profile_image_url": "ユーザーアイコン画像URL"
        }
    },
    ....
]

OAuth認証

さて、このデータを取得するにはOAuth認証を行う必要があります。OAuth認証とはユーザー名とパスワードの代わりにトークンを使って認証する方法で、ユーザーが自分のパスワードをアプリケーションに預ける必要がないのでより安全にアプリケーションを利用することができます。TwitterではすべてのAPIについてOAuth認証が必要になります。

JSON

JSONは主にウェブクライアントでJavaScriotとのデータ受け渡しに使われるデータ形式です。

Twitter4J

TwitterAPIをJavaで簡単に実装することができるライブラリです。今回Twitterに認証してタイムラインを取得する処理はこのライブラリを利用します。ライセンスはApache License 2.0を採用しています。

Twitterのアカウントを用意する

Twitterアカウントを持っていなければ、作成しましょう。

アプリケーションをTwitterに登録する

次のURLを開きTwitterアカウントでログインします。 https://dev.twitter.com/apps 「Create an app」をクリックしてアプリケーションを登録します。以下の項目を入力してください。 Name:アプリケーション名を入力します。 Description:アプリケーションの説明を入力します Website:アプリケーションの情報が入手可能なページを登録します。自身のウェブサイトやブログのアドレスなどを入力します。 Callback URL:Webアプリケーションの場合は認証後にコールバックされるアドレスを入力するのですが、今回のAndroidアプリでは使用しませんので任意のアドレスを入力しておけば良いでしょう。 必要な情報を入力して「Create your Twitter application」をクリックします。 すると、アプリケーションの情報が登録されます。DetailsタブのOAuth settingに表示されているConsumer keyとConsumer secretは、後でOAuth認証に必要となりますので控えておきましょう。

サンプルを作ってみよう

Twitterのホームタイムラインを取得し、取得したタイムラインに含まれているユーザー名をログに出力、LogCatで確認してみましょう。

設定項目

入力値/選択項目

New Android Application Application name

Twitter

Project Name Twitter
Package Name jp.andsys.android.twitter
Build SDK Android 2.1(API 7)
Minimum Required SDK API7:Android 2.1(Eclair)
Create Activity Create Activity BlankActivity
New Blank Activity Activity Name TwitterActivity
Layout Name main
Navigation Type None
Hierarchical Parent (指定なし)
Title Twitter

インターネットに接続するのでマニフェストを追記します。 <uses-permission android:name="android.permission.INTERNET"/>

Twitter4Jをプロジェクトに組み込む

http://twitter4j.org/ のサイトよりライブラリをダウンロードします。現在の最新安定バージョンは バージョン2.2.6です。ダウンロードより、twitter4j-android-2.2.6.zip(Android向けのスリムバージョン)をダウンロードします。 ダウンロードしたファイルをTwitterプロジェクトに追加しましょう。ダウンロードしたtwitter4j-android-2.2.6.zipファイルを展開してください。展開したlibフォルダ内にあるtwitter4j-core-android-2.2.6.jarファイルを、プロジェクトのlibsフォルダにドラッグ&ドロップします。すると「ファイル操作」ダイアログが開くので「ファイルをコピー」を選択して、「OK」をクリックしてプロジェクトにコピーします。

認証用Activityをつくる

Twitterの認証画面を開き認証後のトークンを受け取るためのActivityを作成します。 CONSUMER_KEY定数とCONSUMER_SECRET定数は、さきほどTwitterの開発者サイトで取得したConsumer keyとConsumer secretの文字列をセットしてください。 OAuthActivity.java [java] package jp.andsys.android.twitter; import twitter4j.TwitterException; import twitter4j.auth.AccessToken; import twitter4j.auth.OAuthAuthorization; import twitter4j.auth.RequestToken; import twitter4j.conf.Configuration; import twitter4j.conf.ConfigurationContext; import android.app.Activity; import android.content.Intent; import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; public class OAuthActivity extends Activity { public static final String CONSUMER_KEY = "<取得したConsumer keyをここに>"; public static final String CONSUMER_SECRET = "<取得したConsumer secretをここに>"; private static final String CALLBACK_URL = "callback://TwitterActivity"; private RequestToken mReq = null; private OAuthAuthorization mOAuth = null; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); new OAuthTask().execute(); // 1 } @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); TokenTask task = new TokenTask(); // 2 task.execute(intent); } /* * @param intent / private void getAccessToken(Intent intent) { Uri uri = intent.getData(); if (uri != null && uri.toString().startsWith(CALLBACK_URL)) { String verifier = uri.getQueryParameter("oauth_verifier"); try { AccessToken at = mOAuth.getOAuthAccessToken(mReq, verifier); String accessToken = at.getToken(); // 3 String accessTokenSecret = at.getTokenSecret(); // 4 Intent main = new Intent(this,TwitterActivity.class); main.putExtra("accessToken", accessToken); main.putExtra("accessTokenSecret", accessTokenSecret); startActivity(main); // 5 } catch (Exception e) { e.printStackTrace(); } } } private void executeOauth(){ //Twitetr4jの設定を読み込む Configuration conf = ConfigurationContext.getInstance(); //Oauth認証オブジェクト作成 mOAuth = new OAuthAuthorization(conf); // 6 //Oauth認証オブジェクトにconsumerKeyとconsumerSecretを設定 mOAuth.setOAuthConsumer(CONSUMER_KEY, CONSUMER_SECRET); // 7 //アプリの認証オブジェクト作成 try { mReq = mOAuth.getOAuthRequestToken(CALLBACK_URL); // 8 } catch (TwitterException e) { e.printStackTrace(); finish(); } String uri; uri = mReq.getAuthorizationURL(); // 9 startActivity(new Intent(Intent.ACTION_VIEW , Uri.parse(_uri))); // 10 } class OAuthTask extends AsyncTask<void,Void,Void>{ @Override protected Void doInBackground(Void... arg0) { executeOauth(); // 11 return null; } } class TokenTask extends AsyncTask<intent,Void,Void>{ @Override protected Void doInBackground(Intent... params) { getAccessToken(params[0]); // 12 return null; } @Override protected void onPostExecute(Void result) { finish(); } } [/java] 追加したOAuthActivityが呼ばれるようにAndroidManifestに追記します。アプリケーションを起動したらまずOAuthActivityが実行されるようにします。 AndroidManifest.xml [xml] <manifest> ・・・省略・・・ <application android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name=".TwitterActivity" android:label="@string/title_activity_twitter" > </activity> <activity android:name=".OAuthActivity" android:launchMode="singleTask" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> <intent-filter> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> <data android:scheme="callback" /> <data android:host="TwitterActivity" /> </intent-filter> </activity> </application> </manifest> [/xml] OAuthActivityが起動するとOAuthTaskが呼ばれます(1)。OAuthTaskはAsyncTaskを継承したクラスで、別スレッドでexecuteOauthメソッドを実行しています(11)。 executeOauthメソッドはTwitter4Jの認証オブジェクトを作成し(6)、認証画面を開くためのインテントを作成・発行しています。この時、Oauth認証オブジェクトにconsumerKeyとconsumerSecretを設定しておきます(7)。また認証が完了したあとに呼ばれるコールバックURIとして"callback://TwitterActivity"を指定しています(8)。このURIインテントフィルターに設定されているアクティビティを呼び出して認証結果を渡します。 認証用URLを取得し(9)、それをURIにセットしたインテントを作成して発行します(10)。 インテントが発行されると、ブラウザが開き、Twitterの認証画面が表示されます。認証画面でTwitterのユーザーID、パスワードを入力し、認証を行います。 認証後には再びOAuthActivityが開きます。これは認証を行うと、AndroidManifestでOAuthActivityのインテントフィルタに、

<data android:scheme="callback" />
<data android:host="TwitterActivity" />

と、先程のコールバックURLを指定することで、認証が完了したあとには再びOAuthActivityが呼ばれるようにしています。再びOAuthActivityが呼ばれるとOAuthActivityのonNewIntentメソッドが実行されます。これはアクティビティにandroid:launchMode="singleTask"を指定しているためです。通常、アクティビティが呼ばれると新しいインスタンスが生成されるのですが、singleTaskモードでは、同時に存在できるアクティビティのインスタンスはひとつだけとなり、再度呼ばれた時にはonNewIntentメソッドが呼び出されます。 onNewIntentではTokenTaskを実行して認証の結果を受け取ります(2)。TokenTaskはAsyncTaskを継承したクラスで、別スレッドでgetAccessTokenメソッドを実行します(12)。 getAccessTokenメソッドでは、TwitterとのOAuth認証に必要になる「Access token」と「Acces token select」という文字列を取得しています(3・4)。以降、TwitterAPIとのやり取りにはこの2つの文字列が必要になりますので、取得した文字列をインテントに追加データ(Extra)として格納し、TwitterActivityに渡しています(5)。

新規Javaファイルの作成

ツイート1件分のステータス情報を格納するためのクラス Status.java [java] package jp.andsys.android.twitter; public class Status { private String text; // ツイート内容 private String screenName; // ユーザー名 private String profileImageUrl; // アイコン画像URL public String getText() { return text; } public void setText(String text) { this.text = text; } public String getScreenName() { return screenName; } public void setScreenName(String screenName) { this.screenName = screenName; } public String getProfileImageUrl() { return profileImageUrl; } public void setProfileImageUrl(String profileImageUrl) { this.profileImageUrl = profileImageUrl; } } [/java]

アクティビティの編集

TwitterActivity.java [java] package jp.andsys.android.twitter; import java.util.ArrayList; import java.util.Iterator; import twitter4j.ResponseList; import twitter4j.Twitter; import twitter4j.TwitterException; import twitter4j.TwitterFactory; import twitter4j.conf.Configuration; import twitter4j.conf.ConfigurationBuilder; import android.app.Activity; import android.os.Bundle; import android.util.Log; public class TwitterActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); ArrayList<Status> list = parseTimeline(); if (list != null) { for (Iterator<Status> iterator = list.iterator(); iterator .hasNext();) { Status status = (Status) iterator.next(); Log.d("parse", status.getScreenName()); } } } // タイムラインを表示します。 private ArrayList<Status> parseTimeline() { ArrayList<Status> list = new ArrayList<Status>(); String accessToken = getIntent().getStringExtra("accessToken"); // 1 String accessTokenSelect = getIntent().getStringExtra("accessTokenSecret"); // 2 ConfigurationBuilder cbuilder = new ConfigurationBuilder(); cbuilder.setOAuthConsumerKey(OAuthActivity.CONSUMER_KEY); cbuilder.setOAuthConsumerSecret(OAuthActivity.CONSUMER_SECRET); cbuilder.setOAuthAccessToken(accessToken); cbuilder.setOAuthAccessTokenSecret(accessTokenSelect); // 3 cbuilder.setRestBaseURL("https://api.twitter.com/1.1/"); Configuration conf = cbuilder.build(); TwitterFactory twitterFactory = new TwitterFactory(conf); Twitter mTwitter = twitterFactory.getInstance(); ResponseList<twitter4j.Status> statuses; try { statuses = mTwitter.getHomeTimeline(); // 4 for (twitter4j.Status status : statuses) { Status s = new Status(); s.setScreenName(status.getUser().getScreenName()); s.setProfileImageUrl(status.getUser().getProfileImageURL() .toString()); // 5 s.setText(status.getText()); list.add(s); } } catch (TwitterException e) { e.printStackTrace(); } return list; } } [/java] TwitterJSONデータの取得と解析はTwitter4Jを使います。 OAuthActivityから渡された「Access token」と「Acces token select」をインテントから取り出します(1・2)。 まず、OAuthActivityで取得した「Access token」と「Acces token select」、さらに「Consumer key」、「Consumer secret」およびRESTベースURLを指定してConfigurationオブジェクトを作成します。そこからTwitter4JのTwitterオブジェクトを生成します(3)。 Twitterオブジェクトが作成できれば、あとはgetHomeTimeline()メソッドを呼び出せばホームタイムラインの情報が取得できます(4)。取得した情報はtwitter4j.Statusというクラスオブジェクトのリストとして得られます。取得した情報からユーザー名、ユーザーアイコン画像URL、ツイート本文を抜き出して、先ほど用意したStatusクラスのオブジェクトに格納してリストとして返すようにしています(5)。 Twitter4Jの各メソッドについての詳しい内容は次のURLを参照してください。 URL:http://twitter4j.org/

実行!

アプリケーションが起動すると、ブラウザが立ち上がりTwitterの認証画面が開きます。 任意のTwitterユーザー名、パスワードを入力して「連携アプリを認証」をタップします。 ブラウザが閉じHello world!が表示されます。また、EclipseのLogCatビューにタイムラインのユーザー名が表示されればOKです。

アプリケーションエラーで実行できない場合の対処

11-07 05:45:50.317: W/System.err(594): 401:Authentication credentials
(https://dev.twitter.com/docs/auth) were missing or incorrect.
Ensure that you have set valid consumer key/secret, access token/secret,
and the system clock is in sync.

これは、Consumer keyとConsumer secretの設定間違いや、エミュレータや実機の時刻が正しくない場合に発生します。Consumer keyとConsumer secretの値を確認し、エミュレータや実機の時刻を現在時刻に設定してください。エミュレータの場合、次の手順で現在時刻を設定します。

  1. ホーム画面で「Menu」ボタンをクリックします。
  2. 「設定」を選択します。
  3. 設定画面が開くので「日付と時刻」を選択します。
  4. 「自動」のチェックを外します。
  5. タイムゾーンの選択」を選択します。一覧から「日本標準時(東京)」を選択します。
  6. 「日付設定」を選択して現在の日付を設定します。
  7. 「時刻設定」を選択して現在の時刻を設定します。

テスト中に急にTwitterAPIにアクセスできなくなる場合

TwitterAPI1.1では同じIPアドレスからのアクセス回数は15分に最大15回までと制限されています。接続できていたのに急に接続できなくなった場合は15分後に再度テストしてみてください。