ラベル nfc の投稿を表示しています。 すべての投稿を表示
ラベル nfc の投稿を表示しています。 すべての投稿を表示

2013年2月4日月曜日

Google Playに誘導するNFCタグを作る




Google Playに誘導するNFCタグを作りました。
イベントなどで自作アプリを紹介する際、実際にダウンロードしてもらう良い手段だと思います。


Google PlayへのURL

Google PlayへのURLはこちらを参照。
Linking to Product Detail Page:
http://developer.android.com/distribute/googleplay/promote/linking.html


以下は詳細画面へのURLの例です。
From a web site:
http://play.google.com/store/apps/details?id=<package_name>
From an Android app:
market://details?id=<package_name>


Google Playアプリは「http:」でも反応します。Android端末以外のユーザーにも見てもらうために、「market:」ではなく「http:」を使用することをお薦めします。


NFCタグへの書き込み

Google Playアプリ詳細画面へのURLをNFCタグに書き込みます。
NDEF規格への書き込み例です。
手順
  1. NdefRecord#createUriでNDEFレコードを生成
  2. NDEFメッセージを生成
  3. Writeする

        NdefRecord rtdUriRecords[] = {
                // Google Playの詳細ページURL
                NdefRecord.createUri("http://play.google.com/store/apps/details?id=jp.baroqueworksdev.twiccamushroom")
        };
        NdefMessage ndefMsg = new NdefMessage(rtdUriRecords);
        Ndef ndef = Ndef.get(tag);

        if (ndef.isWritable()) {
            try {
                ndef.connect();
                ndef.writeNdefMessage(ndefMsg);
            } catch (IOException e) {
                e.printStackTrace();
            } catch (FormatException e) {
                e.printStackTrace();
            } finally {
                try {
                    ndef.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

2013年2月3日日曜日

NFCタグを読み込む NdefMessage編

NDEF規格のNFCタグを読み込む方法をまとめます。

参考:NFCタグにURLを書き込む
http://baroqueworksdevjp.blogspot.jp/2013/02/nfcurl.html


Intent-filterの記載

NDEF規格のNFCタグをハンドリングするために、android.nfc.action.NDEF_DISCOVEREDを追加
<intent-filter>
    <action android:name="android.nfc.action.NDEF_DISCOVERED" />
    <category android:name="android.intent.category.DEFAULT" />
    <data android:scheme="http" />
</intent-filter>



IntentからNDEF情報を取得する

IntentのExtra情報:NfcAdapter.EXTRA_NDEF_MESSAGESから、NdefRecordを取得する。
if (getIntent().getAction().equals(NfcAdapter.ACTION_NDEF_DISCOVERED)) {
    Parcelable[] rawMsgs = getIntent().getParcelableArrayExtra(
            NfcAdapter.EXTRA_NDEF_MESSAGES);
    if (rawMsgs != null) {
        for (Parcelable pa : rawMsgs) {
            NdefMessage ndefMsg = (NdefMessage) pa;
            NdefRecord[] records = ndefMsg.getRecords();
            for (NdefRecord rec : records) {
                android.util.Log.e("", "NDEF toString = " + rec.toString());
                // Added in API level 16
                android.util.Log.e("", "NDEF toMimeType = " + rec.toMimeType());
                // Added in API level 16
                android.util.Log.e("", "NDEF toUri = " + rec.toUri());
            }
        }
    }
}

NdefRecord#toMimeType()とNdefRecord#toUri()はAPI Level 16から使用可能。
それ以前のAndroid versionの場合、自分で生成しないといけません。
以下のソースが参考になるかも。
\frameworks\base\core\java\android\nfc\NdefRecord.java


注意点

こんなバグがあるから気を付けよう。
Issue 36968: Scanning an NFC tag without a ndef record results in null pointer exception
http://code.google.com/p/android/issues/detail?id=36968

2013年2月2日土曜日

NFCタグにURLを書き込む

NFCタグシールを購入しました。
価格は一枚あたり約300円でした




このNFCタグへURLの書き込みを行いました。

NdefFormatableのハンドリング

NdefFormatableのTag配信をハンドリングするための準備
AndroidManifest.xmlの記載
NFCを使うためのPermision
<uses-permission android:name="android.permission.NFC" />

<uses-feature
    android:name="android.hardware.nfc"
    android:required="true" />


Intent-filterの追加
<intent-filter>
    <action android:name="android.nfc.action.TECH_DISCOVERED" />

    <category android:name="android.intent.category.DEFAULT" />
</intent-filter>

<meta-data
    android:name="android.nfc.action.TECH_DISCOVERED"
    android:resource="@xml/nfc_tech_list" />


Tech-ListのXmlを作成
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
    <tech-list>
        <tech>android.nfc.tech.NdefFormatable</tech>
    </tech-list>
</resources>


Activity側でTagを受信
IntentからTag情報を取得
if (getIntent().getAction().equals(NfcAdapter.ACTION_TECH_DISCOVERED)) {
    Tag tag = getIntent().getParcelableExtra(NfcAdapter.EXTRA_TAG);
}


NFCタグへURLを書き込む
NdefFormatable.get(tag)でNdefFormatableクラスを取得し、write処理を行う。
    public void write(Tag tag, String uri) {
        NdefRecord rtdUriRecords[] = {
                NdefRecord.createUri(uri)
        };
        NdefFormatable ndef = NdefFormatable.get(tag);
        NdefMessage message = new NdefMessage(rtdUriRecords);
        try {
            ndef.connect();
            ndef.format(message);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (FormatException e) {
            e.printStackTrace();
        } finally {
            try {
                ndef.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

2011年7月30日土曜日

NFCを使ってみる その1


NFCを使用した簡単なアプリを作成しようと思います。
まずはTAGを受け取れるようになるまで。

AndroidManifest.xmlに必要なパラメータを記載

NFCハードウェアを使用するために必要なパーミッションを追加
<uses-permission android:name>"android.permission.NFC" />


AndroidMarketにUpする際、NFC機能搭載端末のみ見えるようにするuses-featureを追加
<uses-feature android:name="android.hardware.nfc" android:required"true" />


ActivityでNFCデータをハンドリングしたい場合、inten-filterを追加
<intent-filter>
    <action android:name="android.nfc.action.NDEF_DISCOVERED"/>
<data android:mimeType="mime/type"/><
/intent-filter>


<intent-filter>
    <action android:name="android.nfc.action.TAG_DISCOVERED"/>
</intent-filter>

<intent-filter>
    <action android:name="android.nfc.action.TECH_DISCOVERED"/>
</intent-filter>
<meta-data android:name="android.nfc.action.TECH_DISCOVERED"
                android:resource="@xml/nfc_tech_filter" />

必要な<intent-filter>を記載しましょう。

<meta-data ・・・>はandroid.nfc.action.TECH_DISCOVERED用のタグです。
プロジェクトの「/res/xml」に 受け取りたいNFC規格を記載した「nfc_tech_filter.xml」を追加します。

詳しくはDeveloperサイトを参照



    android.nfc.tech.IsoDep
    android.nfc.tech.NfcA
    android.nfc.tech.NfcB
    android.nfc.tech.NfcF
    android.nfc.tech.NfcV
    android.nfc.tech.Ndef
    android.nfc.tech.NdefFormatable
    android.nfc.tech.MifareClassic
    android.nfc.tech.MifareUltralight




必要な<tech>タグのみ記載しましょう。

ちなみに、ここに記載する<tech>は「\frameworks\base\core\java\android\nfc\tech」に存在するクラス名です。


これだけで、SuiccaやICOCAなどのFelicaカードを端末にかざすと、android.nfc.action.XXXXのIntentを受けてActivityが起動します。

2011年2月7日月曜日

android2.3のNFCを利用してSuicaの入退場記録を表示

Kazzzさんが公開されている nfc-felica http://code.google.com/p/nfc-felica/ をカスタマイズして入退場記録を表示してみました。
f:id:baroqueworksdev:20110206231651p:image


入退場記録のフォーマット

以下のサイトを参考にしました。
http://jennychan.web.fc2.com/format/suica.html#108F

カスタマイズ箇所

・入退場記録クラスをSuica.javaに追加
public static class Inout {
        final byte[] data;
        Context context;  
        /**
         * コンストラクタ
         * @param data データのバイト列(16バイト)をセット
         * @param context androidコンテキストをセット
         */
        public Inout(byte[] data, Context context) {
            this.data = data;
            this.context = context;
        }
        
        public String getConsoleType(){
         switch(data[0]){
         case (byte) 0x00:return "清算出場";
         case (byte) 0x20:return "出場";
         case (byte) 0x21:return "駅務機器出場";
         case (byte) 0x40:return "定期出場";
         case (byte) 0xA0:return "入場";
         case (byte) 0xC0:return "定期入場";
         }
   return Byte.toString(data[0]);
        }
        /**
         * 入場駅を取得します
         * @return String バスの場合、序数0に会社名、1停留所名が戻ります 
         *  鉄道の場合、序数0に会社名、1に路線名、2に駅名が戻ります
         */
        public String[] getEntranceStation() {
//                if ( this.isByBus() ) {
//                    //バス利用の場合
//                    return getBusStop(Util.toInt(new byte[]{this.data[6], this.data[7]})
//                            , Util.toInt(new byte[]{this.data[8], this.data[9]}));
//                } else {
                    //鉄道利用の場合
                    return getStation(0, this.data[2], this.data[3]);
//                }
        }





        /**
         *  地区コード、線区コード、駅順コードから駅名を取得します
         * 
http://sourceforge.jp/projects/felicalib/wiki/suicaを参考にしています
* @param regionCode 地区コードをセット * @param lineCode 線区コードをセット * @param statioCode 駅順コードをセット * @return 取得できた場合、序数0に会社名、1に路線名、2に駅名が戻ります */ private String[] getStation(int regionCode, int lineCode, int statioCode) { int areaCode = regionCode & 0xff; DBUtil util = new DBUtil(this.context); try { SQLiteDatabase db = util.openDataBase(); Cursor c = db.query(TABLE_STATIONCODE , COLUMNS_STATIONCODE , COLUMNS_STATIONCODE[0] + " = '" + areaCode + "' and " + COLUMNS_STATIONCODE[1] + " = '" + (lineCode & 0xff) + "' and " + COLUMNS_STATIONCODE[2] + " = '" + (statioCode & 0xff) + "'" , null, null, null, COLUMN_ID); return ( c.moveToFirst() ) ? new String[]{ c.getString(3), c.getString(4), c.getString(5)} : new String[]{"???", "???", "???"}; } catch (Exception e) { e.printStackTrace(); return new String[]{"error", "error", "error"}; } finally { util.close(); } } /** * 処理日付(出場日付)を取得します * @return byte[] */ public Date getProccessDate() { int date = Util.toInt(new byte[]{this.data[6], this.data[7]}); int yy = date >> 9; int mm = (date >> 5) & 0xf; int dd = date & 0x1f; int hh = Util.toInt(new byte[]{(byte) ((this.data[8]&0xf0) >> 4) }) * 10 + Util.toInt(new byte[]{(byte) (this.data[8]&0x0f)}); int min = Util.toInt(new byte[]{(byte) ((this.data[9]&0xf0) >> 4) }) * 10 + Util.toInt(new byte[]{(byte) (this.data[9]&0x0f)}); Calendar c = Calendar.getInstance(); c.set(Calendar.YEAR, 2000 + yy); c.set(Calendar.MONTH, mm-1); c.set(Calendar.DAY_OF_MONTH, dd); c.set(Calendar.HOUR_OF_DAY , hh); c.set(Calendar.MINUTE, min); return c.getTime(); } @Override public String toString() { NumberFormat nf = NumberFormat.getCurrencyInstance(); nf.setMaximumFractionDigits(0); SimpleDateFormat dfl = new SimpleDateFormat("yyyy/MM/dd HH:mm"); StringBuilder sb = new StringBuilder(); sb.append("入出場: " + this.getConsoleType() + "\n"); sb.append("日時: " + dfl.format(this.getProccessDate()) + "\n"); String[] entranceInfo = this.getEntranceStation(); sb.append(" 利用会社: " + entranceInfo[0]+ "\n"); sb.append(" 路線名: " + entranceInfo[1]+ "線\n"); sb.append(" 駅名: " + entranceInfo[2] + "\n"); return sb.toString(); } }

・NFCFeliCaReader.javaの入退場記録ボタンを有効化

未解決事項

フォーマットは分かったのですが、以下の事項が未解決です。
・入出場、使用装置種別
  → 0byte目のデータですが、すべての値が判明していない
・地域コードがわからない
  → 路線コード(2byte目)&駅コード(3byte目)は判明しているが、
   レコードの中に地域コードの値がない
・バス利用時は入退場に記録されるのか不明
  → こんどバスに乗ったときに履歴を除いてみます