Android再入門 - Twitterクライアントを作ってみよう - OAuth認証

  • 78
    Like
  • 57
    Comment
More than 1 year has passed since last update.

はじめに

ここでは、AndroidアプリでTwitterのOAuth認証をするところまでを作ります。

OAuth認証画面を作る

まずは、MainActivityはそのままにしてOAuth認証する画面を作りましょう。中央に一つ認証を開始するためのボタンを置いた画面レイアウトを作ります。

レイアウトファイルを作る

  1. res/layout/activity_main.xml をコピペ(Ctrl+C 続けざまに Ctrl+V)して「activity_twitter_oauth.xml」という名前を付けます。

    レイアウトファイルの名前はHogeActivityであればactivity_hoge.xmlという名前をつけることが慣例です。あとで、TwitterOAuthActivityというアクティビティを作るので今回は「activity_twitter_oauth.xml」というファイル名にします。

  2. activity_twitter_oauth.xmlを開いたら、真ん中のTextViewを削除して代わりにButtonを置きます。

  3. android:idを「action_start_oauth」に変更します。

    res/layout/activity_twitter_oauth.xml
    <Button
        android:id="@+id/action_start_oauth"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:text="Button" />
    
  4. android:textを「@string/twitter_oauth」に変更します。すると、まだtwitter_oauthという名前の文字列リソースを定義していないので以下のようにエラーになります(Eclipseのバージョンなど環境によってはならない場合があるかもしれません。その場合はすみません・・・次のショートカットが使えません。もしくは、Runすると強制的にビルドが走ってエラーになります)。

  5. エラーの部分にカーソルがある状態で、Ctrl+1 (MacはCommand+1)を押します。エラーの修正候補を提案してくれます。

  6. そのまま一番上の「Create resource…」を選んだ状態でEnterキーを押すか、ダブルクリックすると、以下のようにres/values/strings.xmlに定義を作成してくれます。

  7. あとは、好きな文字列にしてください。今回は「Twitter認証」にしました。

  8. レイアウトファイルに戻ってボタンのテキストが表示されているか確認してください。

アクティビティを作る

次に、OAuth認証する画面のアクティビティを作りましょう。

  1. TwitterOAuthActivityという名前のクラスを新しく作成します。アクティビティなのでandroid.app.Activityを継承します。

  2. 以下のようにonCreate()メソッドを定義してレイアウトファイルを指定します。

    TwitterOAuthActivity.java
    
    package com.example.mytwitter;
    
    import android.app.Activity;
    import android.os.Bundle;
    
    public class TwitterOAuthActivity extends Activity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_twitter_oauth);
        }
    }
    
  3. AndroidManifest.xmlにアクティビティの定義を追加します。アクティビティを追加するたびにマニフェストファイルに定義をする必要があるので忘れないように注意してください。

    AndroidManifest.xml
    <activity android:name=".TwitterOAuthActivity" />
    

    念のため、追加したあとの全体は以下のようになります。

    AndroidManifest.xml
    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.example.mytwitter"
        android:versionCode="1"
        android:versionName="1.0" >
    
        <uses-sdk
            android:minSdkVersion="8"
            android:targetSdkVersion="17" />
    
        <application
            android:allowBackup="true"
            android:icon="@drawable/ic_launcher"
            android:label="@string/app_name"
            android:theme="@style/AppTheme" >
            <activity
                android:name="com.example.mytwitter.MainActivity"
                android:label="@string/app_name" >
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
    
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
            <activity android:name=".TwitterOAuthActivity" />
        </application>
    
    </manifest>
    

    MainAcitivtyはパッケージ名を含めたクラス名で定義されていますが、上記のようにルートパッケージからの相対的な書き方でもOKです。

  4. MainActivityでアクセストークンが保存されていなければ(認証済みでなければ)TwitterOAuthActivityを呼び出すようにします。TwitterOAuthActivityを呼び出したあとはfinish()メソッドでMainActivityを終了させてBackキーなどで戻ってしまってMainActivityが表示されないようにします。

    MainActivity.java
    package com.example.mytwitter;
    
    import android.app.Activity;
    import android.content.Intent;
    import android.os.Bundle;
    import android.view.Menu;
    
    public class MainActivity extends Activity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            if (!TwitterUtils.hasAccessToken(this)) {
                Intent intent = new Intent(this, TwitterOAuthActivity.class);
                startActivity(intent);
                finish();
            }
        }
    
        @Override
        public boolean onCreateOptionsMenu(Menu menu) {
            // Inflate the menu; this adds items to the action bar if it is present.
            getMenuInflater().inflate(R.menu.activity_main, menu);
            return true;
        }
    
    }
    
  5. 実行してみましょう。以下のようにTwitterOAuthActivityの画面が表示されればOKです。

ボタンが押されたら認証を開始する

次に、ボタンが押されたら認証を開始して、認証後、アクセストークンを保存するところまで作りましょう。

コールバックの設定

まず、ブラウザでのOAuth認証後にアプリにコールバックして戻ってくる仕組みの準備をします。

  1. AndroidManifest.xmlでTwitterOAuthActivityの定義を以下のように変更します。

    AndroidManifest.xml
    <activity
        android:name=".TwitterOAuthActivity"
        android:launchMode="singleTask" >
        <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:host="twitter"
                android:scheme="gabu" />
        </intent-filter>
    </activity>
    

    android:launchMode="singleTask"は、ブラウザからアクティビティが呼び出された時に二重起動しないようにする設定です。
    <intent-filter>で起動する条件を設定します。そして、以下の部分が肝になります。

    <data
        android:host="twitter"
        android:scheme="gabu" />
    

    上記のようにすると gabu://twitter というURLにアクティビティが反応するようになります。この gabu://twitter の部分がコールバックURLです。普通、URLというと http://google.com のように書きますが、そうしてしまうと普通にブラウザでページを読んでいるだけでアクティビティが反応して起動してしまうので、アプリ独自のスキームを定義しているというわけです。

  2. コールバックURL gabu://twitter を文字列リソースに定義します。

    res/values/strings.xml
    <?xml version="1.0" encoding="utf-8"?>
    <resources>
    
        <string name="app_name">MyTwitter</string>
        …省略
        <string name="twitter_callback_url">gabu://twitter</string>
    

アクティビティに実装

それでは、ボタンが押されてから認証が完了するまでの処理をアクティビティに実装しましょう。

TwitterOAuthActivity.java
package com.example.mytwitter;

import twitter4j.Twitter;
import twitter4j.TwitterException;
import twitter4j.auth.AccessToken;
import twitter4j.auth.RequestToken;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;

public class TwitterOAuthActivity extends Activity {

    private String mCallbackURL;
    private Twitter mTwitter;
    private RequestToken mRequestToken;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_twitter_oauth);

        mCallbackURL = getString(R.string.twitter_callback_url);
        mTwitter = TwitterUtils.getTwitterInstance(this);

        findViewById(R.id.action_start_oauth).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startAuthorize();
            }
        });
    }

    /**
     * OAuth認証(厳密には認可)を開始します。
     * 
     * @param listener
     */
    private void startAuthorize() {
        AsyncTask<Void, Void, String> task = new AsyncTask<Void, Void, String>() {
            @Override
            protected String doInBackground(Void... params) {
                try {
                    mRequestToken = mTwitter.getOAuthRequestToken(mCallbackURL);
                    return mRequestToken.getAuthorizationURL();
                } catch (TwitterException e) {
                    e.printStackTrace();
                }
                return null;
            }

            @Override
            protected void onPostExecute(String url) {
                if (url != null) {
                    Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
                    startActivity(intent);
                } else {
                    // 失敗。。。
                }
            }
        };
        task.execute();
    }

    @Override
    public void onNewIntent(Intent intent) {
        if (intent == null
                || intent.getData() == null
                || !intent.getData().toString().startsWith(mCallbackURL)) {
            return;
        }
        String verifier = intent.getData().getQueryParameter("oauth_verifier");

        AsyncTask<String, Void, AccessToken> task = new AsyncTask<String, Void, AccessToken>() {
            @Override
            protected AccessToken doInBackground(String... params) {
                try {
                    return mTwitter.getOAuthAccessToken(mRequestToken, params[0]);
                } catch (TwitterException e) {
                    e.printStackTrace();
                }
                return null;
            }

            @Override
            protected void onPostExecute(AccessToken accessToken) {
                if (accessToken != null) {
                    // 認証成功!
                    showToast("認証成功!");
                    successOAuth(accessToken);
                } else {
                    // 認証失敗。。。
                    showToast("認証失敗。。。");
                }
            }
        };
        task.execute(verifier);
    }

    private void successOAuth(AccessToken accessToken) {
        TwitterUtils.storeAccessToken(this, accessToken);
        Intent intent = new Intent(this, MainActivity.class);
        startActivity(intent);
        finish();
    }

    private void showToast(String text) {
        Toast.makeText(this, text, Toast.LENGTH_SHORT).show();
    }
}

パーミッションを追加

Twitter4Jでインターネットを使ってAPIにアクセスするため、「インターネットを使う」というパーミッションが必要です。マニフェストファイルに以下のパーミッションを追加します。

AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.mytwitter"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="17" />

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

動かしてみる

実行してTwitterのOAuth認証をしてみましょう。最後に、「認証成功!」とトーストが表示されて、MainActivityが表示されればOKです。

起動して

ボタンをタップして

「連携アプリを認証」をタップすると

アプリに戻る!

これでアクセストークンが保存された状態になったので、次回以降アプリを起動すると認証済みの状態で起動します。しかしながら、アクセストークンはプリファレンスに保存しているので、ユーザがデータを消去したりアプリを再インストールするとプリファレンスが削除されて、また認証済みでない状態になります。その場合は、また認証画面が表示されます。認証画面のテストなどしたい場合なども同様にアプリを再インストールするなどしてテストを行います。

以上でOAuth認証まわりの実装は完了です。お疲れ様でした!

目次へ戻る