Archive for the ‘AIR’ Category

6月
07

TranslatAIRのTweet機能をXAuth対応する(準備編)の続きです。

ActionScriptのOAuthライブラリや、twitterのAPIライブラリを使おうかとも思ったのですが、コールするAPIは以下の2つだけなので、今回は自前で作ることにしました。

  • https://api.twitter.com/oauth/access_token(アクセストークンを取得する)
  • http://twitter.com/statuses/update.json(ステータスを更新する)

※ 後者は前から使ってる翻訳結果をtweetするAPIです。

ライブラリのソースコードはかなり参考にさせていただきました。
q-oauth – Project Hosting on Google Code
oauth-as3 – Project Hosting on Google Code
などです。

特にq-outhというライブラリの方には、それをコールするサンプルアプリのソースコードも入っていましたので、非常に参考になりました。

パラメータで必要になってくる署名を生成するところには、ライブラリを利用しています。
as3crypto – Project Hosting on Google Codeというライブラリです。

まずは、アクセストークンを取得します。

●HTTPリクエスト

  • POST

●URL

  • https://api.twitter.com/oauth/access_token

●パラメータ

  • oauth_consumer_key:twitter登録時に発行されるコンシューマキー
  • oauth_nonce:ユニークID
  • oauth_signature_method:HMAC-SHA1固定
  • oauth_timestamp:現在時刻のタイムスタンプ
  • oauth_version:1.0固定
  • x_auth_mode:client_auth固定
  • x_auth_username:twitterアカウント
  • x_auth_password:twitterパスワード
  • oauth_signature:署名

※ 署名を生成する部分は後述します。

●応答結果

  • oauth_token:アクセストークン
  • oauth_token_secret:署名キー
  • user_id:twitter側で管理しているユーザID(だと思います)
  • screen_name:表示名
  • x_auth_expires:トークンの有効期限

※ このうち上2つを使います。
※ 有効期限は0が返ってくるので無期限になります。

やりかたはいろいろあると思いますが、私はまず、XAuthでのみ使用する情報をまとめるモデルクラスを作りました。

ソースコードはこんな感じです。
※ 6、7行目のキーはアプリケーション登録時に発行されるものに読み替えてください。

package
{
	public class XAuthModel
	{
		private static var access_token_url:String = "https://api.twitter.com/oauth/access_token"
		private static var consumer_key:String = "Consumer key";
		private static var consumer_secret:String = "Consumer secret";
		private var _status:String;
		private var oauth_token:String;
		private var oauth_token_secret:String;
		private var oauth_signature:String;
		private var _authorized:Boolean;

		public function XAuthModel()
		{
			_status = "";
			oauth_token = "";
			oauth_token_secret = "";
			oauth_signature = "";
			_authorized = false;
		}

		public function get AccessTokenUrl():String {
			return access_token_url;
		}

		public function set Status(status:String):void {
			_status = status;
		}

		public function get Status():String {
			return _status;
		}

		public function set OAuthSignature(signature:String):void {
			oauth_signature = signature;
		}

		public function get OAuthSignature():String {
			return oauth_signature;
		}

		public function set OAuthToken(token:String):void {
			oauth_token = token;
		}

		public function get OAuthToken():String {
			return oauth_token;
		}

		public function set OAuthTokenSecret(secret:String):void {
			oauth_token_secret = secret;
		}

		public function get OAuthTokenSecret():String {
			return oauth_token_secret;
		}

		public function get ConsumerKey():String {
			return consumer_key;
		}

		public function get ConsumerSecret():String {
			return consumer_secret;
		}

		public function set isAuthorized(authorized:Boolean):void {
			_authorized = authorized;
		}

		public function get isAuthorized():Boolean {
			return _authorized;
		}

	}
}

アクセストークンを取得する部分はこんな感じです(ちょっと長いですが)。
※ 49、50行目のusername、passwordは、適宜置き換えてください。

package
{
	import com.adobe.serialization.json.JSON;
	import com.hurlant.crypto.Crypto;
	import com.hurlant.crypto.hash.HMAC;
	import com.hurlant.util.Base64;
	import com.hurlant.util.Hex;

	import flash.net.URLVariables;
	import flash.utils.ByteArray;

	import mx.rpc.events.FaultEvent;
	import mx.rpc.events.ResultEvent;
	import mx.rpc.http.HTTPService;
	import mx.utils.UIDUtil;

	public class TwitterManager
	{
		private var _model:XAuthModel;

		public function TwitterManager()
		{
		}

		public function initTwitterManager(model:XAuthModel):void {
			_model = model;
		}

		public function Tweet(message:String):void {
			if (!_model.isAuthorized) {
				getAuthToken(message);
			}
			else {
				//setStatus(message);
			}
		}

		private function getAuthToken(status:String):void {
			_model.Status = status;

			var requestTokenService:HTTPService = new HTTPService();
			requestTokenService.method = "POST";
			requestTokenService.url = _model.AccessTokenUrl;
			requestTokenService.addEventListener(ResultEvent.RESULT, onAuthTokenResult);
			requestTokenService.addEventListener(FaultEvent.FAULT, onAuthTokenFault);

			var forms:URLVariables = new URLVariables();
			forms.x_auth_mode = "client_auth";
			forms.x_auth_password = "password";
			forms.x_auth_username = "username";
			forms.oauth_signature = getSignature(requestTokenService.method, requestTokenService.url, forms);

 			requestTokenService.request = forms;
			requestTokenService.send();
		}

		private function getSignature(method:String, url:String, forms:URLVariables):String {
			var now:Date = new Date();

			forms.oauth_consumer_key = _model.ConsumerKey;
			forms.oauth_nonce = UIDUtil.getUID(now);
			forms.oauth_signature_method = "HMAC-SHA1";
			forms.oauth_timestamp = now.time.toString().substring(0, 10);
			forms.oauth_version = "1.0";
			if (_model.OAuthToken.length) {
				forms.oauth_token = _model.OAuthToken;
			}

			var sortArr:Array = UrlVariableToArray(forms);
			var sigBase:String = URLEncoding.encode(method) + "&" +  URLEncoding.encode(url)  + "&" + URLEncoding.encode(sortArr.join("&"));
			var sigkeybase:String = URLEncoding.encode(_model.ConsumerSecret) + "&";
			if (_model.OAuthTokenSecret.length){
				sigkeybase += URLEncoding.encode(_model.OAuthTokenSecret);
			}

			var hmac:HMAC = Crypto.getHMAC("sha1");
			var sig_key:ByteArray = Hex.toArray(Hex.fromString(sigkeybase));

			var data:ByteArray = Hex.toArray(Hex.fromString(sigBase));
			var signature:String = Base64.encodeByteArray(hmac.compute(sig_key, data));

			return signature;
		}

		private function UrlVariableToArray(variables:URLVariables):Array{
			var arr:Array = new Array();
			for(var key:String in variables){
				arr.push(key + "=" + URLEncoding.encode(variables[key]));
			}
			arr.sort();
			return arr;
		}

		private function onAuthTokenResult(event:ResultEvent):void {
			var results:Array  = event.result.toString().split("&");

			for each (var token:String in results) {
				if (_model.OAuthToken == "" || _model.OAuthTokenSecret == "") {
					var values:Array = token.split("=");

					if (values.length == 2) {
						if (values[0] == "oauth_token") {
							_model.OAuthToken = values[1];
						}
						else if (values[0] == "oauth_token_secret") {
							_model.OAuthTokenSecret = values[1];
						}
					}
				}
				else {
					break;
				}
			}

			_model.isAuthorized = true;
		}

		private function onAuthTokenFault(event:FaultEvent):void {
			trace("投稿失敗...\n" + event.fault.toString());
		}
	}
}

57~83行目のgetSignature関数は署名を生成する処理です。
SHA1方式のハッシュ値を署名として、パラメータに付加します。

●対象となるテキスト

  • HTTPリクエスト:POST
  • URL:コールするAPIのURL
  • パラメータ:POSTするパラメータのキーと値を「&」ですべて繋げたもの

これらをURLエンコードして、さらに「&」で繋げます。

●署名キー

  • consumer_secret
但し、ActionScriptの関数、encodeURIComponentではエンコードできない文字があるようです(「!」「*」とか)。
Extended UTF-8 in OAuth ActionScript library
こちらのソースコードを、ものすごく参考にさせていただきました!

Twitter API Wiki / Twitter REST API Method: oauth access_token for xAuthには、署名の対象となるテキストの一例があります。こんな感じになります。

Example Signature Base String:

POST&https%3A%2F%2Fapi.twitter.com%2Foauth%2Faccess_token&oauth_consumer_key%3Dri8JxYK2ZdwSV5xIUfNNvQ%26oauth_nonce%3DqfQ4ux5qRH9GaH8tVwDCwInLy6z8snR6wiq8lKcD6s%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1267817662%26oauth_version%3D1.0%26x_auth_mode%3Dclient_auth%26x_auth_password%3Dxyz12242134%26x_auth_username%3Depisod

翻訳結果をtweetするところも基本的には同じですが、不要なパラメータと追加するパラメータ、追加する署名キーがあります。

●不要なパラメータ

  • x_auth_mode
  • x_auth_username
  • x_auth_password

※ アクセストークンが取得できているので、これらを再度送る必要はありません。

●追加するパラメータ

  • oauth_token

●追加する署名キー

  • oauth_token_secret

※ このキーを追加するのはgetSignature関数に実装されています。

tweetするところは、こんな感じです。

		private function setStatus(status:String):void {
			var updateService:HTTPService = new HTTPService;
			updateService.method = "POST";
			updateService.url = "http://twitter.com/statuses/update.json";
			updateService.resultFormat = "text";
			updateService.addEventListener(ResultEvent.RESULT, onResult);
			updateService.addEventListener(FaultEvent.FAULT, onFault);

			var forms:URLVariables = new URLVariables();
			forms.status = status;
			forms.oauth_signature = getSignature(updateService.method, updateService.url, forms);
			updateService.request = forms;
			updateService.send();
		}

		private function onResult(event:ResultEvent):void {
			var json:Object = JSON.decode(event.result.toString());
			trace(json.text);
		}

		private function onFault(event:FaultEvent):void {
			trace("投稿失敗...\n" + event.fault.toString());
		}

このソースコードを上のTwitterManagerクラスに付け足し、setStatus関数をコールするコードを、onAuthTokenResult(コールバック)関数の最後に付け足せば、XAuthで認証した流れで、翻訳結果をtweetすることが出来るようになります。

ということで、XAuth対応したTranslatAIR、是非使ってみてください!

サンプルソース

5月
30

google翻訳APIを使ったAIRアプリを作る!(Twitterに投稿編)でtwitterのAPIでサポートされている認証は、OAuth方式とBASIC認証と書きました。

Twitter API 仕様書 第二十版 (2009年4月16日版) より引用(2009/12/8時点の最新版です)。

どうやら、OAuth認証とBASIC認証をサポートしているようです。
とりあえずBASIC認証を使うことにします。

現在はXAuth方式もサポートされています。
ですが、BASIC認証が2010年6月30日に廃止されます。

以前リリースした簡易翻訳AIRアプリケーション、TranslatAIRが翻訳結果をtweetするという機能を持っていますが、BASIC認証を採用しているので、利用する認証方式を変更したいと思います。

@twitterapi’s countdown to Basic Auth removalでBASIC認証廃止へのカウントダウンが開始されています。

OAuthとは?

簡潔に説明するのはむずかしいので、参考サイトをご紹介します。
APIアクセス権を委譲するプロトコル、OAuthを知る - @IT

さらに調べていると、図付きでわかりやすいサイトを見つけました。あわせてこちらもどうぞ。
※ twitterの例ではありませんが、概念は同じです。パラメータも一部twitterのものと異なります。
Yahoo!デベロッパーネットワーク – OAuth – フロー

XAuthとは?

OAuthの簡易版といったところでしょうか。
Yahoo!デベロッパーネットワーク – OAuth – フローにある、処理フローの図で言うところの「3.Access Tokenの取得」のみで認証します。
※ 付加するパラメータはOAuthのものとは異なります。

OAuthでは、サービスプロバイダの同意画面を表示させるためにブラウザが立ち上がりますが、ブラウザが起動できない、起動したくない、または、ブラウザを起動するのがふさわしくないような場合、XAuthを使います。

一番の違いは、ID、パスワードの取り扱いです。OAuthの場合は、サービスプロバイダ側に預けるのに対し、XAuthの場合は、それを実装しているクライアント側(コンシューマ)に預けることになります。つまり、クライアントに預けたID、パスワードを悪用される危険性が全くないとは言えないということです。これは、XAuthのデメリットであり、クライアントを使うユーザに対する脅威ですので、開発するにあたっては、このリスクを十分理解しないといけません。

とはいうものの、一般的には、WebアプリではOAuthを、デスクトップアプリではXAuthを使うという感じで、使い分けられているようです。

今回はXAuth方式を採用したいと思います。

実装前の準備

前置きが長くなりましたが、今回はtwitterでXAuth方式を使う際の下準備についてまとめたいと思います。

1.アプリケーション登録申請
Create cool applications! | dev.twitter.comにアクセスし、「Register an app」を選択します。

top

twitterのアカウントでログインします。

login

アプリケーション登録申請画面が開きますので、項目を入力します。

app

「アプリケーションを登録する」ボタンをクリックすると、同意画面が表示されます。

agree

「I Accept」を選択します。

translatair

アプリケーションの登録申請が完了しました!

2.メールで申請
ちょこちょこっとサンプルコードを書いて試していたところ、以下のようなエラーが出て、一向に進みません。

[RPC Fault faultString="HTTP 要求に関するエラー" faultCode="Server.Error.Request" faultDetail="エラー : [IOErrorEvent type="ioError" bubbles=false cancelable=false eventPhase=2 text="Error #2032: Stream Error. URL: https://api.twitter.com/oauth/access_token" errorID=2032]. URL: https://api.twitter.com/oauth/access_token”]

Twitter API Wiki / Twitter REST API Method: oauth access_token for xAuthをよく読むと、以下のようにありました。

In order to get access to this method, you must apply by sending an email to api@twitter.com ― all other applications will receive an HTTP 401 error. Web-based applications will not be granted access, except on a temporary basis for when they are converting from basic-authentication support to full OAuth support.

OAuth方式を使用する場合は必要ないようなのですが、XAuth方式を利用する際にはメールでapi@twitter.com宛てに申請して、許可をもらわないといけないようです。ちょっとだけはまりました。要注意です。

以下のような内容でメールしました。

タイトル:access_token for xAuth
本文:Hi. My name is mojyamojya in twitter. Please my application to use the xauth. The application name is TranslatAIR.

以前は、何度もやり取りしないとなかなか許可がもらえず、とても手間がかかったようですが、私の場合、サクッと解決しました。メールしたのは深夜だったのですが、翌朝には「XAuth、もう使えるようになってるよ」的な返事が来ていました。ラッキーです。

以上が、デスクトップアプリケーションがtwitterのAPIコール時にXAuth方式を利用するまでに必要な下準備です。実装編は、次回ご紹介したいと思います。

3月
29

flashcast:フリーで働くITエンジニア集団のブログ: FeliCa & Adobe AIR/Adobe Flashアプリケーションコンテストに応募しましたっ!で、ソニーさん主催のコンテストに応募した、

Love FeliCa

が、なんと「モバイル部門賞」を受賞しました!

ソニーさんとAdobeさんのサイトにも、受賞作品として掲載されました。
FeliCa & Adobe® AIR®/Adobe® Flash®アプリケーションコンテスト受賞者リスト « SDK for AIR/Flashブログ
Adobe Edge: 2010年3月 FeliCa & AIR/Flashアプリケーションコンテスト 最優秀賞は「Felica交換日記」

今回は、flashcastメンバーの合作でコンテストに応募するという初の試みでしたが、賞をいただけたという最高の結果で締めくくることができ、非常に達成感を感じております。

反省点としては、、、
Flash Liteのコンテンツ、携帯サイトもあるのですが、携帯電話で閲覧するものなので、プレゼンなどでは紹介しづらいアプリケーションとなってしまったことです。今回はプレゼンをする機会はなかったのですが、今後は、そういったことも意識しつつ面白いアプリケーションを開発していけたら、と思います。

他にも優れた作品がたくさんありますので、興味がある方は、いろいろ試してみるのも面白いと思います!

是非、試してみてください!

Love FeliCa

3月
08

2010年に年を越してしばらくした頃、以下のような記事を見つけました。

FeliCa & Adobe AIR/Adobe Flash アプリケーションコンテスト開催のお知らせ! « SDK for AIR/Flashブログ

お題はFeliCaを使ったAIRかFlashのアプリケーションで、技術的に優れているか、アイデアのユニークさなどを競うというものです。面白そうなので、やってみないかとflashcastのメンバーに投げかけてみたところ、いくつか良い案が挙がってきたました。期間もあまり無かったのですが、アイデアで勝負!ということで、チャレンジしてみることにしました。

採用したのは、ろっきー案の「FeliCaで相性占い」です。

2つのおサイフケータイから、IDmというFeliCaに一意に振られる(といわれている)キー情報を取得し、その組み合わせから相性占いをするといった、ゲーム感覚のアプリケーションです。

パソコン搭載型FeliCaポートか、USBで接続されているパソリにおサイフケータイを1台づつかざしていきます。2つのIDmを検知したところで相性占いを開始し、その結果を表示するためのURLをおサイフケータイに送信します。後は、おサイフケータイで、そのURLにアクセスすると相性占いの結果が見れ、その結果とともにコメントを携帯サイトに残すことができるという一連の仕組みになっています。

詳細はこちらをご覧ください。

アプリケーションの構成は、おサイフケータイを検知したり、URLをおサイフケータイに送信したりする「AIRアプリケーション」、相性占いの結果を表示するための「Flashコンテンツ(Flash Lite)」、また、その結果とともにコメントを書き込みするための「携帯サイト」の3つで構成されています。

後者の2つはサーバ上に配置されていますので、搭載型FeliCaポートかパソリが接続されているパソコン上で動作するのは「AIRアプリケーション」になります。

期間も短かったこともあり、ろっきーともじゃもじゃの2人で、役割分担して進めました。

名前はLove FeliCaにしてみました。

審査結果は、明日、2010/3/9(火) ICカードワールド2010で発表されるようです。このイベントには参加できませんが、どんな結果になるか楽しみです。結果はともかく、参加したことに意義があると思っています!また、今回はコンテスト向けアプリケーションとして開発しましたが、今までにない分野へのチャレンジでもあったので、これを今後に生かして、なにか良いアイデアが出てきたら、また、何か作ってみたいと思います!

技術的な部分は、今後、当ブログで紹介していきたいと思います!
興味がわいた方、是非試してみてください!

12月
21

やっと、アプリが完成したので、リリースしましたっ!

名前は、TranslatAIRです。翻訳するAIRアプリということで、translateとAIRを合体してつくった造語です。

基本機能は、今までブログに書いてきたものと同等ですが、いくつか機能を追加しました。

  1. 翻訳結果を表示する機能。
  2. 任意の文章を翻訳する機能。
  3. 翻訳履歴を保存・閲覧する機能。
  4. 設定変更機能
  5. クリップボードの中身を翻訳結果に差し替える機能。

などです。

1は説明するのが難しいのですが、「小さい画面にじわっと浮き出て、じわっと消えていく」と言った感じでしょうか。

info1info2info3info4info5

2、3、4に関しては各画面を用意しました。

翻訳画面

翻訳画面

翻訳履歴画面

翻訳履歴画面

設定変更画面

設定変更画面

これらの画面を呼び出すためのメニューを、アイコンのところに実装しました。

menu

5のクリップボードの中身を翻訳結果に差し替える機能は、その名前の通りで、翻訳後にペーストすると、中身が翻訳されているといった感じになります。

と、こんなところでしょうか。
詳しくはこちらをご覧ください。

以外に便利だと思いますので、是非、使ってみてください!

TranslatAIR

  • Search:
  • flashcastとは?

    東京を中心に、現在フリーランスとして活動しているITエンジニア、および、かつてフリーランスとして活動していた起業家達が立ち上げたコミュニティーです。

    みんなで集まって面白いことをやろう!形に残そう!ということで、ブログをはじめました。

    技術情報や、フリーエンジニアに役立つ情報などを、ご紹介できたらと思っています。

    お問い合わせ:
    info@flashcast.jp
  • カレンダー

    2010年7月
    日曜日 月曜日 火曜日 水曜日 木曜日 金曜日 土曜日
    « 6月    
     123
    45678910
    11121314151617
    18192021222324
    25262728293031
  • メンバー紹介

    もじゃもじゃ
    flashcastのリーダー

    3年ほどフリーのITエンジニアとして活動。現在は、社員2名の株式会社を経営しています。

    一攫千金を夢見る野心家です。

    ライブキャスト

    yasu
    ダイバー

    自宅サーバーでホームページを作り始めました。

    少しずつ記事を増やしていきますので足を運んでください。

    よろしくお願いします。

    sa-sa-ki.jp

    のら
    たびびと

    ねこ好きに悪人はいなーいっ!!

    バイクや車も好きです。

    めぐ
    デザイナーのたまご

    音楽とデザインとお酒をこよなく愛する永遠のダイエッター。

    現在ペンタブレットでイラストを勉強中。

    Hiro
    コンサル

    PMやSEの案件を業務委託で請けることが多いですが、小規模案件も受託でやっています。

    得意な分野はマイクロソフト製品や関連技術によるシステム構築です。

    KEI
    取締役の風格

    最年少なのに、メンバーで1番の貫禄の持ち主!?

    C#や.netなどサーバ側の開発が得意。

    ろっきー
    美食家★パパ

    自分にとっての息抜きは、ドライブして温泉に入って、美味しいご飯を食べる事。

    ココロとカラダのリフレッシュを大切にし、日々の仕事に励む一児の父親です。

    郵便番号検索

    my-hobby

    とのさま
    げーむのおうさま

    大人なのに好きなことしかやらない駄目人間。

    Web系が得意、アクセスは苦手><

    tonosamart.com

    セクレタリアト
    ギャンブラー

    フリーランス時代は仲間の現場を探すことが多く、それをきっかけに会社を設立。

    現在はSI業に特化せず、他の業種にも興味を持ち始めています。

    メドレー株式会社

  • 広告