More Related Content
Similar to Type 4 andefを自力で読む (20)
Type 4 andefを自力で読む
- 2. やりたいこと
• HCE を使ってなんちゃって Type4A NDEF タグを
作ってみた
– http://www.slideshare.net/hieroadgjmptw/hcetype4
• それを読もうと Android 端末を近づけると
「タップしてビーム」とか言われてぐんにょり
• Android – Android で確実にカード読み取りを
したかったら、enableReaderMode() を使って読
む必要がありそう
• せっかくなので、俺はこの赤い扉…じゃなくて
enableReaderMode() を使ったアプリを作るぜ
2
- 3. enableReaderMode
• public
void enableReaderMode (Activity activity, NfcAdapter.ReaderC
allback callback, int flags, Bundle extras)
• Android 4.4 で追加された API (Level 19)
• 端末の NFC カード機能、P2P 機能を停止し、純
粋なリーダー/ライターとして動作させるため
の API
– disableReaderMode() が呼ばれるか、アプリがサス
ペンドするまで有効
• flags の指定次第で、Type A のみ、NDEF の自
動解析をしない、といった動作指定ができる
• P2P 機能を停止できるので、「タップしてビー
ム」とかいわれてぐんにょりしない
3
- 4. Type 4A NDEF リーダーを作る
• 簡単3ステップ
① enableReaderMode を使い、端末の NFC 動作を
「Type A 通信のみ、NDEF 自動解析はしない」に設
定
② 対向タグが見つかったら、NfcA でタグに接続
③ あとは自力で NDEF タグアプリの選択から NDEF
データの読み込みまで行う
• 次のスライドから上記のざっくりした解説
4
- 5. ①端末の NFC 動作設定
• アプリレジューム時に enableReaderMode を呼
び出すだけ
– FLAG_READER_NFC_A … TypeA 通信する
– FLAG_READER_SKIP_NDEF_CHECK … システムで自動的に行う NDEF 解析
を停める
@Override
public void onResume(){
super.onResume();
mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
mNfcAdapter.enableReaderMode(this, this, NfcAdapter.FLAG_READER_NFC_A |
NfcAdapter.FLAG_READER_SKIP_NDEF_CHECK, null);
}
@Override
public void onPause(){
super.onPause();
mNfcAdapter.disableReaderMode(this);
}
5
- 6. ②NfcA でタグに接続する
• 対向機にかざされたら NfcA で接続
@Override
public void onTagDiscovered(Tag tag) {
NfcA nfcA = null;
try {
nfcA = NfcA.get(tag);
nfcA.connect();
… (NDEF の読み込み(後述)) …
} catch (IOException e) {
Log.e(APPNAME, e.toString());
e.printStackTrace();
} catch (TagLostException e) {
Log.e(APPNAME, e.toString());
e.printStackTrace();
}
6
- 7. ③NDEFタグ選択~NDEF読み込み
• 下記流れになる
自機
対向機
NDEF Tag Application(D2760000850101) の選択
成功(9000)
CC File (E103h) の選択
成功(9000)
CC File (15bytes) の読み込み
CC File 情報 + 成功(9000)
NDEF File (File の ID は CC File から読み込み) の選択
成功(9000)
NDEF サイズ確認(先頭 2bytes 読み込み)
サイズ情報(2bytes) +成功(9000)
NDEF 読み込み(2バイト目からサイズ情報 bytes 読み込み)
NDEF 情報+成功(9000)
7
- 8. ③NDEFタグ選択~NDEF読み込み
final String NDEF_APP = "D2760000850101";
final String CCFILE_EF = "E103";
final String SELECT_BY_DF = "A40400";
final String SELECT_BY_EF = "A4000C";
final String READ_BINARY = "B0";
final byte[] SUCCESS = {(byte)0x90, (byte)0x00};
…
toast("start reading type4 ndef card", Toast.LENGTH_SHORT);
byte[] response = nfcA.transceive(strToHex("00"+SELECT_BY_DF+String.format("%02x", NDEF_APP.length()/2)+NDEF_APP+"00"));
if(!Arrays.equals(response, SUCCESS)) return;
toast( "select Cc File", Toast.LENGTH_SHORT);
response = nfcA.transceive(strToHex("00"+SELECT_BY_EF+String.format("%02x", CCFILE_EF.length()/2)+CCFILE_EF));
if(!Arrays.equals(response, SUCCESS)) return;
toast("read Cc File", Toast.LENGTH_SHORT);
response = nfcA.transceive(strToHex("00"+READ_BINARY+"00000F"));
if(response.length != 17) return;
CcFile ccFile = new CcFile();
ccFile.set(Arrays.copyOfRange(response, 0, 15));
toast("select NDEF File", Toast.LENGTH_SHORT);
ByteBuffer cmd = ByteBuffer.allocate(7);
cmd.put(strToHex("00"+SELECT_BY_EF+"02"));
cmd.put(ccFile.ndefFileControl.fileId);
response = nfcA.transceive(cmd.array());
if(!Arrays.equals(response, SUCCESS)) return;c
8
- 9. ③NDEFタグ選択~NDEF読み込み
toast("read NDEF File", Toast.LENGTH_SHORT);
response = nfcA.transceive(strToHex("00"+READ_BINARY+"000002"));
int ndefLength = response[0]*256+response[1]; // 適当…符号大丈夫かな?
if(ndefLength >= 256) return; // とりあえず大きい NDEF ファイルは弾くことにする
ByteBuffer cmd2 = ByteBuffer.allocate(5);
cmd2.put(strToHex("00"+READ_BINARY+"0002"));
cmd2.put((byte)ndefLength);
response = nfcA.transceive(cmd2.array());
if(response.length!=ndefLength+2){
Log.e(APPNAME, "response is too short, expeted:"+ndefLength+"+2, but returned"+response.length);
return;
}
byte[] rawNdef = Arrays.copyOfRange(response, 0, ndefLength);
try {
NdefMessage ndefMessage = new NdefMessage(rawNdef);
} catch (FormatException e) {
Log.e(APPNAME, e.toString());
e.printStackTrace();
}
toast("read completed!", Toast.LENGTH_LONG);
// あとは NdefMessage を使って好きなように・・・
…
9
- 10. ③NDEFタグ選択~NDEF読み込み
…
private byte[] strToHex(String str){
int length = str.length();
if(length%2!=0)return null;
length = length /2;
byte[] ret = new byte[length];
for(int i=0; i < length; i++){
ret[i] = (byte)Integer.parseInt(str.substring(i*2, (i+1)*2),16);
}
return ret;
}
private void toast(final String str, final int opt){
runOnUiThread(new Runnable(){
@Override
public void run(){
Toast.makeText(getApplicationContext(), str, opt).show();
}
});
}
10
- 11. やってみて
• Android Beam を OFF にしていても、Andoird
と Android を近づけると自動的に LLCP 接続が
走ってしまいカード読み取りできないので、
enableReaderMode() が必要
• なんか妙に TagLostException が発生しちゃう
なあ
– Bundle で EXTRA_READER_PRESENCE_CHECK_DELAY を
設定してあげたらマシになるんやろうか
11