2011年6月アーカイブ

twitter4j_oauth.png

Android で Twitter4J を使用し、Twitter の OAuth 処理を行うクラスを作成しました。

特徴としては、動的に WebView を作成し、コールバックページのフックをソースコードで記述しているため、

リソースファイルや AndroidManifest.xml への独自スキーマのための定義が不要であり、

本クラス(1ファイル)を導入するだけで認証できるようになります

※もちろん AndroidManifest.xml への Activity の追加は必要です^^;

※Android 1.5 以降 + twitter4j-android-2.2.2 で確認済

2011/6/5追記:環境によってはshouldOverrideUrlLoading()でフックできない場合があるようです(謎)。
その場合、onPageStarted()で代替できますので、そちらをお使いください。。。

※2012/6/16追記:サンプルコードは http://code.google.com/p/adakoda-android-sample/ に置いてあります。
ライセンスは Apache License 2.0 です。

 

使い方

  • 呼び出し方法

OAuth画面をさせるには、自アプリ用のコールバック文字列、認証用文字列をインテントに設定して呼び出すだけ。

Intent intent = new Intent(this, OAuthActivity.class);
intent.putExtra(OAuthActivity.CALLBACK, CALLBACK);
intent.putExtra(OAuthActivity.CONSUMER_KEY, CONSUMER_KEY);
intent.putExtra(OAuthActivity.CONSUMER_SECRET, CONSUMER_SECRET);
startActivityForResult(intent, REQUEST_OAUTH);

 

  • 結果の取得方法

認証結果は、呼び出し元のonActivityResult()でインテントにセットして返されますので、必要な情報を取得するだけ。

long userId = data.getLongExtra(OAuthActivity.USER_ID, 0);
String screenName = data.getStringExtra(OAuthActivity.SCREEN_NAME);
String token = data.getStringExtra(OAuthActivity.TOKEN);
String tokenSecret = data.getStringExtra(OAuthActivity.TOKEN_SECRET);                

 

OAuth 認証コード(一部)

さて、(何故か)ここでお題。。。

認証処理で必要な処理のうち、getOAuthRequestToken() と getOAuthAccessToken() メソッドは、

呼び出しに時間のかかる処理であり、メイン(UI)スレッドでは呼び出してはいけない処理です。

以下では、AsyncTask で実装しましたが、コードも長くなり、いささか気持ち悪いです。

他にも Thread + Handler などの実装方法が考えられますが、もっとスマートな書き方はないでしょうか?

もっといい書き方あるよ!という方は、Twitter で(ry...

public class OAuthActivity extends Activity {

    // Activity開始時のインテントパラメータ
    public static final String CALLBACK = "callback";
    public static final String CONSUMER_KEY = "consumer_key";
    public static final String CONSUMER_SECRET = "consumer_secret";

    // Activity終了時のインテントパラメータ
    public static final String USER_ID = "user_id";
    public static final String SCREEN_NAME = "screen_name";
    public static final String TOKEN = "token";
    public static final String TOKEN_SECRET = "token_secret";

    private static final String OAUTH_VERIFIER = "oauth_verifier";
    
    private WebView mWebView;
    private String mCallback;
    private Twitter mTwitter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setResult(Activity.RESULT_CANCELED);

        // プログレス表示
        requestWindowFeature(Window.FEATURE_PROGRESS);
        requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);

        // Viewのセットアップ
        mWebView = new WebView(this);
        WebSettings webSettings = mWebView.getSettings();
        webSettings.setSavePassword(false);
        mWebView.setWebChromeClient(mWebChromeClient);
        mWebView.setWebViewClient(mWebViewClient);
        setContentView(mWebView);

        // TwitterのOAuth認証画面で毎回ユーザ名、アカウントを入力させるために必要
        CookieManager cookieManager = CookieManager.getInstance();
        cookieManager.setAcceptCookie(false);

        Intent intent = getIntent();
        mCallback = intent.getStringExtra(CALLBACK);
        String consumerKey = intent.getStringExtra(CONSUMER_KEY);
        String consumerSecret = intent.getStringExtra(CONSUMER_SECRET);
        if ((mCallback == null) || (consumerKey == null)
                || (consumerSecret == null)) {
            finish();
        }

        mTwitter = new TwitterFactory().getInstance();
        mTwitter.setOAuthConsumer(consumerKey, consumerSecret);

        PreTask preTask = new PreTask();
        preTask.execute();
    }

    // 前処理
    public class PreTask extends AsyncTask<Void, Void, String> {

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            setProgressBarIndeterminateVisibility(true);
        }

        @Override
        protected String doInBackground(Void... params) {
            String authorizationUrl = null;
            try {
                // 非同期処理が必要なメソッドの呼び出し
                RequestToken requestToken = mTwitter.getOAuthRequestToken();
                if (requestToken != null) {
                    authorizationUrl = requestToken.getAuthorizationURL();
                }
            } catch (TwitterException e) {
                e.printStackTrace();
            }
            return authorizationUrl;
        }

        @Override
        protected void onPostExecute(String result) {
            super.onPostExecute(result);
            setProgressBarIndeterminateVisibility(false);
            if (result != null) {
                mWebView.loadUrl(result);
            } else {
                finish();
            }
        }

    }

    private WebChromeClient mWebChromeClient = new WebChromeClient() {

        @Override
        public void onProgressChanged(WebView view, int newProgress) {
            super.onProgressChanged(view, newProgress);
            setProgress(newProgress * 100);
        }

    };

    private WebViewClient mWebViewClient = new WebViewClient() {

        // 特定のページをフック
        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url) {
            boolean result = true;
            if ((url != null) && (url.startsWith(mCallback))) {
                Uri uri = Uri.parse(url);
                String oAuthVerifier = uri.getQueryParameter(OAUTH_VERIFIER);
                PostTask postTask = new PostTask();
                postTask.execute(oAuthVerifier);
            } else {
                result = super.shouldOverrideUrlLoading(view, url);
            }
            return result;
        }

    };

    // 後処理
    public class PostTask extends AsyncTask<String, Void, AccessToken> {

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            setProgressBarIndeterminateVisibility(true);
        }

        @Override
        protected AccessToken doInBackground(String... params) {
            AccessToken accessToken = null;
            if (params != null) {
                try {
                    // 非同期処理が必要なメソッドの呼び出し
                    accessToken = mTwitter.getOAuthAccessToken(params[0]);
                } catch (TwitterException e) {
                    e.printStackTrace();
                }
            }
            return accessToken;
        }

        @Override
        protected void onPostExecute(AccessToken result) {
            super.onPostExecute(result);
            setProgressBarIndeterminateVisibility(false);
            if (result != null) {
                long userId = result.getUserId();
                String screenName = result.getScreenName();
                String token = result.getToken();
                String tokenSecret = result.getTokenSecret();
                Intent intent = new Intent();
                intent.putExtra(USER_ID, userId);
                intent.putExtra(SCREEN_NAME, screenName);
                intent.putExtra(TOKEN, token);
                intent.putExtra(TOKEN_SECRET, tokenSecret);
                setResult(Activity.RESULT_OK, intent);
            }
            finish();
        }

    }

}

2011年6月1日、Googleの「+1(プラスワン)」ボタンをWebサイトに設置できるようになりました。

 

早速、本サイトにも埋め込んでみましたが、

既に設置している「はてぶ」「ツイート」ボタンに対して、どのような影響を与えるのか興味津々です。

試しに押してみてください。。。((((;゚Д゚)))).。oO(バクハツシマセンカラ)

 

+1 ボタンとは

 

設置方法 ※Movable Type 4.22ja の例

1. 以下のリンク先にアクセスし、ボタンを表示するために必要なコードを取得する

http://www.google.com/webmasters/+1/button/index.html

2  Movable Type にアクセスし、「デザイン」 > 「テンプレートの編集」 を表示する

3. 「ブログ記事」と「ブログ記事の概要」を編集し、以下を参考に <g:plusone></g:plusone> を追加する。

...
<div id="entry-<$mt:EntryID$>" class="entry-asset asset hentry">
    <div class="asset-header"
        <h1 id="page-title" class="asset-name entry-title"><$mt:EntryTitle$></h1>
        <div class="asset-meta">
            <span class="byline">
                  <!-- 次のタグを +1 ボタンを表示する箇所に貼り付けてください -->
                  <g:plusone size="medium" href="<$mt:EntryPermalink$>"></g:plusone>
            </span>
        </div>
...

4. 「HTMLヘッダー」を編集し、以下を参考に plusone.js をインクルードするコードを追加する。

<meta http-equiv="Content-Type" content="text/html; charset=<$mt:PublishCharset$>" />
<meta name="generator" content="<$mt:ProductName version="1"$>" />
<link rel="stylesheet" href="<$mt:Link template="styles"$>" type="text/css" />
...
<!-- 次のタグを head 要素内または body 終了タグの直前に貼り付けてください -->
<script type="text/javascript" src="http://apis.google.com/js/plusone.js"> {lang: &apos;ja&apos;} </script>

 

あわせて読みたい

1

2016年8月

  1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31