Twitterクライアント開発の初歩の初歩 8


Pocket

AndroidでTwitterクライアントを作ったり、自前のアプリにタイムラインを表示したりする方法です。

java環境ではTwitter4Jという素晴らしいライブラリがあるので、これを使って作っていきます(Ver4.0.0を使用)。
#感謝感謝(TдT)です!

 

手順

  1. Twitter Developersでアプリを登録
  2. クライアントアプリの作成
    • OAuth認証をしてAccessTokenを取得する
    • AccessTokenを使ってつぶやいてみる

 

1.Twitter Developersでアプリ登録

まずは作成するアプリがTwitterAPIを使用できるようにするため、Twitter DevelopersでTwitterアプリを登録します。

Twitter Developersにアクセスして、メニューから“My applications”を選択
Twitter Developers

 
“Create New App”をクリック
Create New App

 
・アプリ情報の入力
Create Application

Name:アプリの名前
Description:アプリの説明
Website:アプリのURL
 ・・・アンドロイドアプリの場合はサイトないので適当(自分のTwitterページとか)に入力しておけばいいみたいです)
Callback URL:OAuth後にTwitter認証ページからコールバックさせたいURL
 ・・・これもアンドロイドアプリの場合はアプリ内で設定するので未入力でいいです

ちなみに、ここで設定した内容が認証ページに反映されるようです。

認証画面

 
・アプリを作ったら“API Keys”タブでAPI KeyとAPI secretをメモっておきます。後で作るプログラム内で使います。
#あとこれが漏れると簡単にアプリ乗っ取られるので管理は慎重に!

API KEYS

 
・次に“Permissions”タブでアクセス権限の設定をします。
permissions

タイムライン見るだけなら「Read only」でよくて、アプリ内でツイートとかする場合は「Read and Write」という具合に、作るアプリに適した権限を選びましょう。

しかし、ここではハマった!
Read and Writeに変更すると下記エラーが!!
permissionエラー

詳細を見に行くとなにやらツイッタープロフィールで携帯電話番号を登録しないといけないらしい・・・が!?プロフィール設定にそんな項目ないし??

モバイル設定

と思ったら、言語設定を英語にしたら出てきた・・・。

モバイル設定

よしこれで進めると思ったら・・・登録できない・・・何やら日本の電話会社はまだサポート外みたいですね・・・あれっこれ積んだ?

困ったときは慌てずググる(`・ω・´)キリッ

どうやらメール通知設定で携帯のメールアドレス登録すればいいみたいです。
<参考にさせて頂いたページ>
Twitterのアプリケーション新規登録時に、開発者のTwitterアカウントと携帯電話の関連付けが必須になった模様。

メールアドレス登録してしばらく待つと・・・できた。Permissionを「Read and Write」に変更することができました。

以上でTwitterDevelopersでの設定は終わりです。
さてさて、次はソフトを作っていきます。

 

 

2.クライアントアプリの作成

2.0.Twitter4Jライブラリの組込み

Twitter4Jからライブラリをダウンロードします。
ZIP解凍して出てきたファイルの
・lib/twitter4j-core-4.0.0.jar
・lib/twitter4j-async-4.0.0.jar
を開発環境のlibsフォルダにコピーします。

#非同期APIを使用するためtwitter4j-asyncも組み込んでいます。同期APIを使用するだけなら不要ですが、Androidの場合はActivityのメインスレッドでhttpリクエストをするとNetworkOnMainThreadExceptionが発生するので、基本通信処理は非同期で実装します

 

2.1.OAuth認証をしてAccessTokenを取得する

初めにアプリがユーザーのアカウントを使用できるようにOAuth認証を行い、ユーザーのAccessTokenを取得します。

public class MainActivity extends Activity {
	private final String API_KEY = "TwitterDevelopersでメモったAPI KEY";
	private final String API_SECRET = "TwitterDevelopersでメモったAPI SECRET";
	
	private AsyncTwitter mTwitter;
	private RequestToken mReqToken;

	private final TwitterListener mListener = new TwitterAdapter() {
		@Override
		public void gotOAuthRequestToken(RequestToken token) {
			mReqToken = token;
			Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(mReqToken.getAuthorizationURL()));
			startActivity(intent);
		}

		@Override
		public void gotOAuthAccessToken(AccessToken token) {
			//token.getToken()とtoken.getTokenSecret()を保存する
		}

	};
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		mTwitter = new AsyncTwitterFactory().getInstance();
		mTwitter.addListener(mListener);
		mTwitter.setOAuthConsumer(API_KEY, API_SECRET);
		mTwitter.getOAuthRequestTokenAsync("twittercallback://callback");
		
	}

	@Override
	protected void onNewIntent(Intent intent) {
		//ブラウザからのコールバックで呼ばれる
		final Uri uri = intent.getData();		
		final String verifier = uri.getQueryParameter("oauth_verifier");
		if (verifier != null) {
			mTwitter.getOAuthAccessTokenAsync(mReqToken, verifier);
		}
	}
}

・AndroidManifest.xml

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

        <activity
            android:name="com.example.twittertest.MainActivity"
            android:label="@string/app_name" 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="twittercallback"/>                
            </intent-filter>
        </activity>

ざっくりしたOAuth処理の流れ

  • 29行目:
  • AsyncTwitterに処理完了時のリスナーを登録する
    getOAuthRequestTokenAsync()に対してgotOAuthRequestTokenAsync()が呼ばれるように、基本的には要求メソッド名の過去形になっているようです
  • 30行目:
  • API KEY、API Secret(Consumer KeyとConsumer Secret)をセット
  • 31行目:
  • RequestTokenの取得要求をService Provider(=Twitter.com)に投げる※別タスクで実行されます
    引数はCallBack先のURL。アンドロイドアプリの場合は自身が呼ばれるように「独自スキームを作りIntentフィルターに設定」「戻り先ActivityのlanchmodeをsingleTaskにする」をManifest.xmlに記述しておく
  • 10-14行目:
  • RequestTokenが取得できたら、それをくっつけてユーザーをService Providerへリダイレクト
    ブラウザを起動してTwitter認証ページにユーザーを誘導しています
  • ブラウザ:
  • ブラウザでユーザーが許可/不許可を選択すると、ブラウザは31行目で設定したURLに認証結果パラメータを付加してコールバックする
  • 36-43行目:
  • ブラウザからのコールバックを受け取ったら、パラメータから”oauth_verifier”を取得し、今度はRequestTokenとoauth_verifierを使ってAccessToken取得要求を投げる
  • 17-19行目:
  • AccessToken、AccessToken Secretが取得できたらそれを保存しておく

OAuth認証は以上です。
一度AccessTokenとAccessToken Secretを取得したら、次回からはそれを使ってTwitterAPIにアクセスできるので、この認証処理は不要になります。

 

2.2.AccessTokenを使ってつぶやいてみる

後はとても簡単。AccessTokenをセットして、各処理を行うメソッドをリスナーと共に実行すればいいだけです。

例えばつぶやくなら、リスナーにupdatedStatus()を実装して、updateStatus()を呼び出します。

#リスナーは基本的には要求メソッドを過去形にしたものが対応付いているようですね(全部は確認していませんが・・・なんとなく)

	private final String API_KEY = "TwitterDevelopersでメモったAPI KEY";
	private final String API_SECRET = "TwitterDevelopersでメモったAPI SECRET";
	private final String ACCESS_TOKEN = "アクセストークン";
	private final String ACCESS_TOKEN_SECRET = "アクセストークンシークレット";
	
	private final TwitterListener mListener = new TwitterAdapter() {
		@Override
		public void updatedStatus(Status status) {
			Log.d("updatedStatus", "Status ID:" + status.getID());
		}

		@Override
		public void searched(QueryResult queryResult) {
			for (Status status : queryResult.getTweets()) Log.d("searched", "Status ID:" + status.getID());
		}

	};
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		mTwitter = new AsyncTwitterFactory().getInstance();
		mTwitter.addListener(mListener);
		mTwitter.setOAuthConsumer(API_KEY, API_SECRET);
		
		AccessToken accessToken = new AccessToken(ACEESS_TOKEN, ACEESS_TOKEN_SECRET);
		mTwitter.setOAuthAceessToken(accessToken);
	}

	//ツイートする
	public void tweet(String text) {
		mTwitter.updateStatus(text);
	}

	//検索する
	public void searchTweet(String text) {
		Query query = new Query();
		query.setQuery(text);
		query.setCount(80); //検索件数
		query.setResultType(Query.RECENT); //日付の新しいものから
		mTwitter.search(query);
	}

#ツイートはtweetじゃなくてupdateStatusなんですね。確かに本家もツイートじゃなくてStatusを更新するっていう扱いですね。へーへー

 

サンプルアプリ

サンプルアプリ

Twitter4Jを使ったサンプルアプリを下記に置いておきますので参考までに。
EditTextに入力文字をツイートしたり検索したりして結果を表示します。

https://github.com/workpiles/TwitterTest

 
 

あとがき

AndroidでTwitterクライアントを作る基本的な部分はこんなところです。思ったより簡単にできましたね(*^^*)

・・・というのもTwitter4Jがめんどくさい通信部分をすべてラップしてくれているからですね。ホント素晴らしいですな(TдT)

今回はAsyncTwitterクラスを使用してみましたが、リスナー処理が別タスクになっているんですね。
そのため、検索完了後に結果を画面に表示しようとした場合、画面更新処理をメインタスクへPostしてあげないといけないのが若干めんどくさかったりもします。
非同期のTwitterクラスを使って通信部分はAsyncTaskで実装した方がコード的にはスッキリするかもしれません。

Twitterを使ってみようと思ったきっかけは、アンドロイドマーケットに出してる「20×20九九トレに」Twitterを使って対戦機能を実装してみたかったからです。プレイゴーストデータを検索して取得するようなことをやりたいとなると、単純にIntent飛ばしてTwitterクライアント起動する方法ではできないので。
Twitter機能実装したアプリも3/25になんとかリリースしてひと段落!

まだツイートする、検索する、リツイートする程度の機能しか触ってませんが・・・今後自前でクライアント機能を実装するようなアプリ作るかな・・・。
機会があればもっと違った機能も動かして見たいと思います。

 
 
 


Leave a Comment

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

次のHTML タグと属性が使えます: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

8 thoughts on “Twitterクライアント開発の初歩の初歩

  • Reply
    M.aoki

    こんにちは!
    このサイトのhttp://workpiles.com/2014/03/android-twitter4j-asynctwitter/
    を参考にTwitter4jやJavaの勉強をさせていただいております。

    質問なのですが、Intentでブラウザ画面に誘導することができなくて困っております。

    状況なのですが、最初の認証画面が出なく、ボタンやエディットテキストが出ます。そしてUpdateStatusを押すと
    LogCatに認証できませんでしたと出ます。
    アクセストークンとアクセストークンシークレットをソースで書いたらつぶやき、検索はすることができました。
    Intentのところを教えていただいてもよろしいでしょうか?

    • Reply
      koike Post author

      こんにちは。

      認証画面が表示されない件ですが、下記を再度確認してみてください。
      (github上のサンプルコードを元に記載しています)

      1.API_KEY、API_SECRETが間違っていないか。
      2.SharedPreferencesに間違った(古い)Token&Secretが残ったままになっていないか。
      3.gotOAuthRequestToken()内のgetAuthorizationURL()でちゃんと認証ページのURL(※1)が取得できているか。
      ※1:https://api.twitter.com/oauth/authorize?oauth_token=*

      認証画面の表示は、getOAuthRequestTokenAsync()に対するgotOAuthRequestToken()がコールされることにより表示されます。
      どちらもちゃんと呼ばれているかをデバッグで確認してみると、解決の手掛かりになるかもしれません。

      以上、コメントの内容から想像出来る範囲で考えてみました。参考になれば幸いです。

      • Reply
        M.aoki

        返信ありがとうございました。
        さっそくデバッグをしてみたところ、どうやらSharedPreferencesに間違った(古い)Token&Secretが残ったままになっていて、
        if (token == null) {
        mTwitter.getOAuthRequestTokenAsync(“twittercallback://callback”);
        } else {
        mTwitter.setOAuthAccessToken(token);
        }
        のところで下のElseの方が選択されているのでIntentで認証画面に誘導されないのではないかと考えました。
        もし、間違ったTokenがSharedPreferencesに残っている場合、どうすればリフレッシュされるのでしょうか?
        お忙しい中すみませんが、よろしくお願いいたします。

  • Reply
    M.aoki

    すみません
    原因が分かったので報告させていただきます。
    Twitter側のCallBackURLを適当に書いたらWebページに飛びました。
    あんまりそのあたりはまだ調べているのでこれが原因かわかりませんが、
    一応問題解決したので報告させていただきました。

    こんな初心者にアドバイスしていただきありがとうございます。Javaの勉強になりました。
    お手数おかけしてすみませんでした。

  • Reply
    ars42525

    2.1.OAuth認証をしてAccessTokenを取得する の部分のソースを使って実装してみたのですが、アプリ起動時に認証画面が出ず、何も表示されません
    認証が成功するかを確認したいので、トークンの保存などはしておらず、古いトークンが残っているということはなさそうです。
    このコードだけでは認証はできないのでしょうか?
    それとも他になにか原因があるのでしょうか?

    • Reply
      koike Post author

      > このコードだけでは認証はできないのでしょうか?
       可能だと思います。
       最新のTwitter4j(4.0.4)で試してみましたが、問題なく認証画面に遷移できました。

      > それとも他になにか原因があるのでしょうか?
       実行環境など不明なためなんとも言えませんが…
       Twitterアプリ側で【Test OAuth】が問題なくうごくか確認してみてはどうでしょう。
       
      以上、参考になれば幸いです。