2010年7月30日金曜日

AndroidでOAuth on twitter

twitter4jを利用してOAuth&twitterのタイムライン取得をするAndroidアプリを作ってみました。
テストアプリなのでアレですが、結構はまったので公開しておきます。

MainActivity.java

package com.example.atwitter;

import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;

import twitter4j.Paging;
import twitter4j.ResponseList;
import twitter4j.Status;
import twitter4j.Twitter;
import twitter4j.TwitterException;
import twitter4j.TwitterFactory;
import twitter4j.User;
import twitter4j.conf.ConfigurationBuilder;
import twitter4j.http.AccessToken;
import twitter4j.http.RequestToken;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends Activity {
    // キー
    private static String CONSUMERKEY ="XXXXXX";
    private static String CONSUMERSECRET ="XXXXXX";
    private static String ACCESSTOKEN ="XXXXXX";
    private static String ACCESSSECRET ="XXXXXX";

    // コールバックURL
    private final String CALLBACK_URL="testapp://atwitter/";
    
    private static String SNL = System.getProperty("line.separator");
    private static String DNL = SNL + SNL;

    // Twitter
    private Twitter twitter;
    private AccessToken accessToken;

    // TextView
    private TextView textView;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        // Twitterの初期化
        initializeTwitter(null);

        // TextViewを保持
        textView = (TextView)findViewById(R.id.TextView01);

        // ボタンにコールバックを登録
        Button button = (Button)findViewById(R.id.Auth);
        button.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                // twitterアクション実行
                String result = doOAuth(twitter);
                textView.setText(result);
            }
        });
        button = (Button)findViewById(R.id.Button01);
        button.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                // twitterアクション実行
                String result = userTimeline(twitter);
                textView.setText(result);
            }
        });
    }

    private void initializeTwitter(AccessToken accessToken) {

        ConfigurationBuilder confBuilder = new ConfigurationBuilder();
        confBuilder.setOAuthConsumerKey(CONSUMERKEY);
        confBuilder.setOAuthConsumerSecret(CONSUMERSECRET);

        TwitterFactory twitterFactory = new TwitterFactory(confBuilder.build());
        twitter = twitterFactory.getOAuthAuthorizedInstance(accessToken);
    }

    public String userTimeline(Twitter twitter){
        ResponseList statuses = null; //
        String result = "print userTimeline:" + DNL;
        int pageNumber =1;
        int count = 20;

        //Paging
        Paging paging = new Paging(pageNumber, count);

        try {
            statuses = twitter.getUserTimeline(paging);

            if (statuses != null) {
                for (Status status :statuses) {
                    result += status.getUser().getScreenName() +":"
                    + SNL + status.getText() + DNL;
                }
            }

        } catch (Exception e) {
            result += e.getMessage();
            e.printStackTrace();
        }
        return result;
    }

    private String doOAuth(Twitter twitter_) {
        String result = "doOAuth:" + DNL;
        Twitter twitter = new TwitterFactory().getInstance();
        twitter.setOAuthConsumer(CONSUMERKEY, CONSUMERSECRET);
        
        // RequestTokenを取得
        RequestToken requestToken = null;
        try {
            requestToken = twitter.getOAuthRequestToken(CALLBACK_URL);
        }
        catch (TwitterException e) {
            result += e.getMessage() + DNL;
            e.printStackTrace();
        }
        
        // RequestTokenを保存
        ObjectOutputStream oos;
        try {
            OutputStream out = openFileOutput("RequestToken", MODE_PRIVATE);
            oos = new ObjectOutputStream(out);
            oos.writeObject(requestToken);
        } catch (Exception e) {
            result += e.getMessage() + DNL;
            e.printStackTrace();
        }

        // 認証ページへ
        String strUrl = requestToken.getAuthorizationURL();
        Uri uri = Uri.parse(strUrl);
        Intent intent = new Intent(Intent.ACTION_VIEW, uri);
        startActivity(intent);

        result += strUrl;
        
        return result;
    }

    // 起動時に呼ばれる(認証完了時も呼ばれる)
    @Override
    public void onResume() {
        super.onResume();

        String result = "";
        // extract the OAUTH access token if it exists
        Uri uri = this.getIntent().getData();
        if (uri != null && uri.toString().startsWith(CALLBACK_URL)) {
            RequestToken requestToken = null;
            try {
                InputStream in = openFileInput("RequestToken");
                ObjectInputStream ois = new ObjectInputStream(in);
                requestToken = (RequestToken)ois.readObject();
            } catch (Exception e) {
                result += e.getMessage() + DNL;
                e.printStackTrace();
            }
            String access_token = uri.getQueryParameter("oauth_verifier");
            try {
                accessToken = twitter.getOAuthAccessToken(requestToken, access_token);
                initializeTwitter(accessToken);
                // ここでAccessTokenを保存しておけば次回から認証不要となる
                textView.setText("認証完了");
            } catch (TwitterException e) {
                result += e.getMessage() + DNL;
                e.printStackTrace();
            }
        }
    }
}
ポイントは、
  • コールバックURLを使って、ブラウザでの認証後にAndroidアプリを起動させる(124行目)
  • 認証後、AccessTokenを生成するため、RequestTokenを保存しておく(131行目〜)
あたりでしょうか。

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.example.atwitter"
      android:versionCode="1"
      android:versionName="1.0">
    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <activity android:name=".MainActivity"
                  android:label="@string/app_name">
            <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="testapp" android:host="atwitter" android:path="/"/>
            </intent-filter>
        </activity>

    </application>
    <uses-sdk android:minSdkVersion="4" />

<uses-permission android:name="android.permission.INTERNET"></uses-permission>

</manifest>
24行目でuses-permissionを使ってINTERNETを許可しています。あと、17行目でコールバックURLをフックしています。

main.xml(layout)

<?xml version="1.0" encoding="utf-8"?>

<FrameLayout android:id="@+id/FrameLayout01" android:layout_width="fill_parent" android:layout_height="fill_parent" xmlns:android="http://schemas.android.com/apk/res/android">
    <TextView android:id="@+id/TextView01" android:layout_height="fill_parent" android:layout_width="fill_parent" android:text="Hello, twitter!"></TextView>
    <LinearLayout android:id="@+id/LinearLayout01" android:layout_height="wrap_content" android:layout_gravity="bottom" android:layout_width="wrap_content">
        <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="認証" android:id="@+id/Auth"></Button>
        <Button android:id="@+id/Button01" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="タイムラインとか"></Button>
    </LinearLayout>
</FrameLayout>
特別なことは何も。

実行例です。認証画面に遷移したところ。

0 件のコメント:

コメントを投稿