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>

 

あわせて読みたい

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/

 

あわせて読みたい

Google I/O 2011 で予定されているセッションのうち、Android 関連のものをピックアップし、表にしてみました。

 

概要

  • Android 関連のセッションは、全部で21セッションある
  • それらは、Room8(2F)、Room9(2F)、Room11(3F)で開催される
  • Room11 のみ LIVE STREAMING される
  • セッションレベルは、101(初級)、201(中級)、301 (上級)の3種類

sessions_color.png

 

2011/5/10 Android 関連セッション

io2011_0510_android.png

 

2011/5/11 Android 関連セッション

io2011_0511_android.png

 

Map

MAP3F.pngMAP2F.png

 

受講したいセッション(adakoda)

starred10.png starred11.png

  • 初日(10日)は、ずっと Room 11
  • 二日目(11日)は、Room 9 > 11 > 8 > 9 > 9
  • 一番興味深いのが、(キャプチャ切れましたが)最後のメモリ管理のセッション

 

※上記表はGoogle Docsで作成しており、以下のリンクからも参照できます

https://spreadsheets.google.com/ccc?key=0AkHlMPkv8YCOdFpZUDJ1V3ZlUk9TS1ZQVkxiTFc4ZkE&hl=ja&authkey=CNqDi7UF

[Android] twicca supporters

| トラックバック(0) |

twicca バージョン 0.9.0RC からアプリ内課金を利用した「twicca サポーター」が追加されました。

 

twicca サポーターとは?

twicca では今後の開発およびメンテナンスを続けるためのサポーターを募集しています。

サポーターの皆さんのお名前は『twiccaについて』の中に掲載させていただきます。

twicca サポーターになるにはサポーターチケットを購入してください。

 

早い話が、今まで「青山さん、俺だ!振込先を教えてくれー!」って言っていた人の思いが通じたということです。

 

購入するには、「メニュー」 > 「その他」 > 「twiccaサポーターズ」を選択後、

日数を選択し、「購入する」ボタンを、ポチるだけです。

※アプリ内課金は有料アプリと異なり、キャンセルできませんので、ご注意ください

※サポーターズチケットは、「7日間(1週間)105円」~選択できるようです(2011年5月5日現在)

 

twicca_supporters.png twicca_supporters2.png

twicca_supporters3.pngtwicca_supporters4.png

twicca_supporters5.png

 

購入後は、「メニュー」 > 「その他」 > 「twiccaについて」から、名前を確認できます。

twicca_supporters6.png

 

こういったアプリ内課金の使い方は、おそらく国内では初?と思われます。

素晴らしいアプリは評価される風土が根付いて欲しいですね。

2011年3月29日、東京電力の最大供給量と使用量を取得できる API が公開されました。

 

同 API については、先日(3月19日~21日)開催された Hack for Japan でも要望のあったものです。

Yahoo!デベロッパーネットワークさん、仕事が早いですね。さすが!

 

API 解説

 

本 API を使用することにより、東電の最大供給量と電力使用量を、XML または JSON 形式で取得できるようです。

ただし、期間限定の API であり、終了日は未定とのことです。

また、 API の使用にあたり、アプリケーションID が必要であり、かつ、

24 時間中 1 アプリケーション ID につき 50000 件のリクエストが上限とのことですので、注意が必要です。

(現実的には、キャッシュサーバー用意する必要あり?)

 

以下、早速 Android から呼び出してみました。

一応、API を簡単に使えるようなラッパークラスを作成し、2 行書けば取得できるようにしています。

※誌面の都合上、エラー処理や諸々省略しています

※完全なコードは、Google Code からチェックアウトできます

 

サンプルソースコード

public class SetsudenClient {
    private String mAppID;
    public SetsudenClient(String appID) {
        mAppID = appID;
    }
    public LatestPowerUsageResult getLatestPowerUsage() {
        LatestPowerUsageResult result = new LatestPowerUsageResult();
        // Build uri
        Uri.Builder uriBuilder = new Uri.Builder();
        uriBuilder.path("http://setsuden.yahooapis.jp/v1/Setsuden/latestPowerUsage");
        uriBuilder.appendQueryParameter("appid", mAppID);
        uriBuilder.appendQueryParameter("output", "json");
        String uri = Uri.decode(uriBuilder.build().toString());
        // Request HTTP GET
        HttpUriRequest httpGet = new HttpGet(uri);
        DefaultHttpClient defaultHttpClient = new DefaultHttpClient();
        try {
            HttpResponse httpResponse = defaultHttpClient.execute(httpGet);
            String stringEntity = EntityUtils.toString(httpResponse.getEntity());
            // Parse JSON result
            JSONObject jsonEntity = new JSONObject(stringEntity);
            if (jsonEntity != null) {
                JSONObject jsonElectricPowerUsage =
                    jsonEntity.optJSONObject("ElectricPowerUsage");
                if (jsonElectricPowerUsage != null) {
                    result.setArea(jsonElectricPowerUsage.optString("Area"));
                    JSONObject jsonUsage =
                        jsonElectricPowerUsage.optJSONObject("Usage");
                    if (jsonUsage != null) {
                        result.setUsageUnit(jsonUsage.optString("@unit"));
                        result.setUsageValue(jsonUsage.optInt("$"));
                    }
                    JSONObject jsonCapacity =
                        jsonElectricPowerUsage.optJSONObject("Capacity");
                    if (jsonCapacity != null) {
                        result.setCapacityUnit(jsonCapacity.optString("@unit"));
                        result.setCapacityValue(jsonCapacity.optInt("$"));
                    }
                    result.setDate(jsonElectricPowerUsage.optString("Date"));
                    result.setHour(jsonElectricPowerUsage.optString("Hour"));
                }
            }
        } catch (ClientProtocolException e) {
        } catch (IOException e) {
        } catch (JSONException e) {
        }
        return result;
    }
}

 

public class SetsudenYahooAPISampleActivity extends Activity {
    private static final String TAG = "SetsudenYahooAPISampleActivity";
    private static final String MY_APP_ID = "XXXXXXXXXX"; // 取得したappidで置き換えてください
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        // 非同期処理
        SetsudenClientTask setsudenClientTask = new SetsudenClientTask();
        setsudenClientTask.execute();
    }
    class SetsudenClientTask extends AsyncTask<Void, Void, LatestPowerUsageResult> {
        protected LatestPowerUsageResult doInBackground(Void... params) {
            // 電力使用状況APIのラッパークラスの呼び出し例
SetsudenClient setsudenClient = new SetsudenClient(MY_APP_ID); return setsudenClient.getLatestPowerUsage(); } protected void onPostExecute(LatestPowerUsageResult result) { // LogCat の出力結果
Log.v(TAG, "Area = " + result.getArea()); Log.v(TAG, "Usage = " + result.getUsageValue() + result.getUsageUnit()); Log.v(TAG, "Capacity = " + result.getCapacityValue() + result.getCapacityUnit()); Log.v(TAG, "Date = " + result.getDate()); Log.v(TAG, "Hour = " + result.getHour()); } } }

 

実行結果(DDMS のLogCat 画面)

ddms_output.png

google_code_android_screen_monitor.png

Android 端末(実機、またはエミュレーター)の画面をリアルタイムで PC 上に表示するツールである

Android Screen Monitor のソースコードを公開しました(Apache License 2.0)。

以下のサイトからチェックアウトできます。

 

android-screen-monitor - Project Hosting on Google Code

http://code.google.com/p/android-screen-monitor/

 

引き続き、製品のデモンストレーション、勉強会などのプレゼンテーション等でお使いいただければと思います^^

Androidify.png

Google から Androidify という Android Robot のアバターを作成できる Android アプリケーションがリリースされました。

 

概要

以下の動画のように、髪型や洋服などを選んでいくだけで、自分好みのアバターが作ることができます。

 

Androidify

以下の公式サイトからインストールすることができます。

※Android2.1以降で動作します
※日本語アプリ名は「Androidメーカー」
※Androidify is an application developed together by Google Creative Lab & Larva Labs.

 

早速作ってみました!

kuroharukakka.png

 。。。

ちなみに作成した画像については保存するだけでなく、他のアプリと共有できますので、Twitter に投稿してみても面白いかもしれません。

 

本日見た限りでは、Twitter のタイムラインに流れていた  「Twicca の作者さん(外部リンク)」 の以下の作品が秀逸でした(似すぎwww)。

R246.png

<<前のページへ 345678910111213

2015年9月

    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