twitter4j_oauth.png

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

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

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

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

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

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

 

使い方

  • 呼び出し方法

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...

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

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>

 

あわせて読みたい

eula.png

アプリでよく使用する End User License Agreement (EULA)

Google I/O 2011 のアプリ(iosched)のソースコードを見ていたら入っていたので、ソース場所を共有しておきます。

 

EulaHelper

 

実装は、Accept されたかどうかを SharedPreferences に保存し、ダイアログ表示するだけのもの。

adk.jpg

Google I/O 2011 で発表された「Open Accessory Development Kit (ADK)」を使ってみました。

 

試した環境

  • Ubuntu 10.10 (64bit)
  • Nexus S 2.3.4
  • Arduino 0022 + adk_release_0512.zip + CapacitiveSense003.zip

 

PC に Arudiono IDE と必要なライブラリをインストールする

1. Arduino Software を ココ からダウンロードし、任意の場所に展開する

2. CapSense library を ココ からダウンロードし、任意の場所に展開する

3. The ADK package を ココ からダウンロードし、任意の場所に展開する

4. (手順)2 で得られたディレクトリ直下に含まれる CapSense.h と CapSense.cpp を

 (手順)1 で得られた arduino/libraries ディレクトリ直下に、新たに CapSense ディレクトリを作成し、

 同ディレクトリ下にコピーする

5. (手順)3 で得られた firmware/arduino_libs/AndroidAccessory ディレクトリと

 firmware/arduino_libs/USB_Host_Shield ディレクトリを、

 (手順)1 で得られた arduino/libraries ディレクトリ直下に(ディレクトリごと)コピーする

<完成図>

arduino を展開したディレクトリの libraries 下の構成が以下のようになっていればOK。

arduino-0022-libraries.png 

 

ADK ボードのファームウェア書き換える

I/O で配布された状態でも動作するのですが、このままだとタッチセンサーが動作しないため、ファームウェアを書き換えます。

1) ADK ボードと PC を USB 接続する

2) PC 側で(コマンドラインから上記でインストールしたディレクトリ直下にある)arduino (IDE)を起動する

3) (arduino IDE)初回起動時、「Select folder for sketches...」のようにディレクトリ選択画面が表示されるので、

 任意のディレクトリを選択し、arduino IDE を起動する

4) Tools > Board > Arduino Mega 2560 を選択する

5) Tools > Serial Port > /dev/ttyUSB0 (名称は環境依存)を選択する

6) File > Open から、(先のインストール手順でダウンロードした)The ADK package に含まれる

 firmware/demokit/demokit.pde を選択し、sketch を開く

7) Sketch > Verify / Compile からコンパイルする(Done compiling. と表示されればOK)

8) File > Upload to I/O Board で ADK ボードに転送する(Done uploading. と表示されればOK)

demokit.png

 

Android 端末に ADK のサンプルアプリをインストールする

1. android コマンドから「Google APIs API Level 10 add-on library」をインストールする

2. Eclipse を起動し、New > Project > Android Project、Create project from existing source で

 (先のインストール手順でダウンロードした)The ADK package に含まれる app プロジェクトを選択、

 Buile Target を Google APIs (Platform 2.3.3) に変更し、Finish

3. プロジェクトをビルドし、PC と Android 端末を USB 接続して、アプリケーションを転送する

 

ADK ボードを Android アプリケーションから操作する!

Android 端末と ADK ボードを接続すると、DemoKit ダイアログが表示されるので OK をタップ。

ADK ボード側の Temp / Light / Buttons / Joystick のセンサー値がアプリ画面の In タブ、

アプリ画面の Out 画面で操作した結果が、ADK ボードに反映されます。

in.png

out.png

adk_board.jpg

 

備考

  • 事前に、Ubuntu への arduino のインストールを sudo apt-get install arduino から実行したため、
    上記手順だけだと、必要なライブラリのインストールが足りないと思います(汗)
    ※ちなみに apt-get からだと arduino 0018 がインストールされますが、
     コンパイルエラーとなるため 0022 の圧縮ファイルをダウンロード・展開し直しました
  • arudino IDE 起動時、
    「java.lang.UnsatisfiedLinkError: no rxtxSerial in java.library.path thrown while loading gnu.io.RXTXCommDriver」
    のようなエラーが出た場合、以下のサイトを参考にエラーを回避できました
    http://colinharrington.net/blog/2010/11/arduino-ubuntu-10-10-maverick-meerkat-no-rxtxserial/

 

あわせて読みたい

<<前のページへ 1234567891011

Android Advent Calendar 2011

2012年2月

      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