最近、ソニーが開発した非接触ICカード技術“FeliCa”への関心が高まっています。先日、SDK for FeliCa AIR/Flash というFlash/AIRからFeliCaを操作出来るSDKがリリースされました。このSDKには、Basic版(無償)とStandard版(有償)があり、機能が制限されていますが、簡単な動作確認であれば、Basic版で十分です。
SDK for FeliCa & Adobe® AIR® / Adobe® Flash®
今回は新しくFlash Builber 4を使用してFlex4で簡単にサンプルを作成してみました。
FeliCaのIDmとPMmを読み取るサンプル
下記の動作には、FeliCaポート/パソリが接続されている事、またFeliCaポートソフトウェアがインストールされている必要があります。FeliCaサンプル
MXMLソースコード
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
minWidth="300" minHeight="200">
<s:TextArea id="textArea" lineHeight="150%" visible="false"/>
<s:Button id="button" label="FeliCa読み込み開始" click="{this._onButtonClick()}"/>
<fx:Script>
<![CDATA[
import com.sony.jp.felica.FeliCaCloseReaderWriterRequest;
import com.sony.jp.felica.FeliCaCloseReaderWriterResponse;
import com.sony.jp.felica.FeliCaControl;
import com.sony.jp.felica.FeliCaOpenReaderWriterAutoRequest;
import com.sony.jp.felica.FeliCaOpenReaderWriterAutoResponse;
import com.sony.jp.felica.FeliCaPollingAndGetCardInformationRequest;
import com.sony.jp.felica.FeliCaPollingAndGetCardInformationResponse;
import com.sony.jp.felica.FeliCaSessionRequest;
import com.sony.jp.felica.FeliCaSessionResponse;
import com.sony.jp.felica.error.FeliCaAccessError;
import com.sony.jp.felica.event.FeliCaStatusEvent;
import com.sony.jp.felica.event.OpenStatusEvent;
import mx.utils.ObjectUtil;
/** FeliCaProxy ポート番号 */
private static const FELICA_PORT:uint = 10250;
/** FeliCaProxy 通信タイムアウト秒数 */
private static const FELICA_TIMEOUT:uint = 10;
/** FeliCaProxy と通信を行うクラス */
private var _felica:FeliCaControl = new FeliCaControl();
/** ポーリング用 Timer (500ミリ秒毎, 20回 = 5秒間) */
private var _pollingTimer:Timer = new Timer(500, 10);
private function _onButtonClick():void
{
this.textArea.width = this.width;
this.textArea.height = this.height;
this.textArea.visible = true;
this.button.visible = false;
this._open();
}
private function _open():void
{
this._felica.responseTimeout = FELICA_TIMEOUT * 1000;
this._felica.addEventListener(OpenStatusEvent.OPEN_COMPLETE, this._onOpenComplete);
this._felica.addEventListener(OpenStatusEvent.OPEN_FAILURE, this._onOpenFailure);
this._felica.open(FELICA_PORT);
}
private function _close():void
{
if (this._pollingTimer.running) {
this._pollingTimer.reset();
}
if (!this._felica.close()) {
this._log('[ NG ] Disconnect FeliCa Proxy Error!');
this._close();
return;
}
this._log('[ OK ] Disconnect FeliCa Proxy.');
}
private function _onOpenComplete(event:OpenStatusEvent):void
{
this._log('[ OK ] Connect FeliCa Proxy.');
this._felica.addEventListener(FeliCaStatusEvent.FELICA_ACCESS_COMPLETE, this._onFelicaAccessComplete);
this._felica.addEventListener(FeliCaStatusEvent.FELICA_ACCESS_FAILURE, this._onFelicaAccessFailure);
this._lock();
}
private function _onOpenFailure(event:OpenStatusEvent):void
{
this._log('[ NG ] Open FeliCa Proxy Error!');
this._log(ObjectUtil.toString(event));
}
private function _lock():void
{
var request:FeliCaSessionRequest = new FeliCaSessionRequest();
request.type = FeliCaSessionRequest.HOLD;
request.lockTimeout = 10;
request.unlockTimeout = 30;
this._felica.access(request);
}
private function _unlock():void
{
var request:FeliCaSessionRequest = new FeliCaSessionRequest();
request.type = FeliCaSessionRequest.RELEASE;
this._felica.access(request);
}
private function _polling():void
{
if (!this._pollingTimer.hasEventListener(TimerEvent.TIMER)) {
this._onPollingTimer();
}
this._pollingTimer.addEventListener(TimerEvent.TIMER, this._onPollingTimer);
this._pollingTimer.addEventListener(TimerEvent.TIMER_COMPLETE, this._onPollingTimerComplete);
this._pollingTimer.start();
}
private function _onPollingTimer(event:TimerEvent = null):void
{
this._log('Polling ...');
var request:FeliCaPollingAndGetCardInformationRequest = new FeliCaPollingAndGetCardInformationRequest();
request.systemCode = 'FFFF';
this._felica.access(request);
}
private function _onPollingTimerComplete(event:TimerEvent):void
{
this._log('[ OK ] Stop Polling.');
this._close();
}
private function _onFelicaAccessComplete(event:FeliCaStatusEvent):void
{
if (event.object is FeliCaSessionResponse) {
var session:FeliCaSessionResponse = event.object as FeliCaSessionResponse;
if (session.type == FeliCaSessionResponse.HOLD) {
this._log('[ OK ] FeliCa Session Hold.');
this._felica.access(new FeliCaOpenReaderWriterAutoRequest());
} else if (session.type == FeliCaSessionResponse.RELEASE) {
this._log('[ OK ] FeliCa Session Release.');
this._close();
}
} else if (event.object is FeliCaOpenReaderWriterAutoResponse) {
this._log('[ OK ] Start Polling.');
this._polling();
} else if (event.object is FeliCaPollingAndGetCardInformationResponse) {
this._log('[ OK ] Open FeliCa Reader/Writer.');
if (this._pollingTimer.running) {
this._pollingTimer.reset();
}
var pgcResponse:FeliCaPollingAndGetCardInformationResponse = event.object as FeliCaPollingAndGetCardInformationResponse;
this._log('\nIDm: ' + pgcResponse.idm);
this._log('PMm: ' + pgcResponse.pmm + "\n");
this._felica.access(new FeliCaCloseReaderWriterRequest());
} else if (event.object is FeliCaCloseReaderWriterResponse) {
this._log('[ OK ] Close FeliCa Reader/Writer.');
this._unlock();
}
}
private function _onFelicaAccessFailure(event:FeliCaStatusEvent):void
{
if (event.object is FeliCaAccessError) {
var feliCaAccessError:FeliCaAccessError = event.object as FeliCaAccessError;
if (feliCaAccessError.rwError == 157) { // Error Code: No FeliCa
return;
}
}
if (event.object is Error) {
var error:Error = event.object as Error;
if (error.errorID == 7011) {
this._log('[ NG ] FeliCa Proxy Timeout Error!');
}
}
this._log('[ NG ] FeliCa Access Error!');
this._log(ObjectUtil.toString(event));
this._close();
}
private function _log(message:String):void
{
this.textArea.appendText(message + "\n");
}
]]>
</fx:Script>
</s:Application>
ダウンロード
Flash Builder 4 プロジェクトダウンロード: FeliCaBasic.zipStandard版(有償)を利用すれば、データ領域にアクセス出来るため、様々な事に応用出来そうな気がします。また、読み取り側の普及次第となりますが、ECサイトの決済サービス等も増えてきそうな気がします。

Twitterに投稿
[...] « Flash/AIR で FeliCa へアクセス [...]
処理が止まらなくメモリを食いつぶされました。
(タスクマネージャで確認したときにはメモリ1.2Gつかってました。)
OSはWindowsXPProffesional ブラウザはIE8です。