Android NFC
ã¡ããã¨NFCã«ã¤ãã¦èª¿ã¹ãã®ã§ã¡ã¢ã
NFCã«ã¯è¦æ ¼ãããã¤ãããããAndroidã§NFCã¨ãã£ãããNFCãã©ã¼ã©ã ä»æ§ã®ãã¨ãæãã
NFCãã©ã¼ã©ã ä»æ§ã®NFCã¯ä¸è¨ã®ï¼ã¤ã«å¯¾å¿ãã¦ãã
NDEF(NFC Data Exchange Format)
NFCã®ã¿ã°ãã©ã¼ãããå½¢å¼ãAndroidã§ç¨ããããå½¢å¼ãNDEFã«æºæ
NDEFã«ã¯(é常)ï¼ã¤ã®NDEF Messageãå«ã¾ããNDEF Messageã«ã¯0å以ä¸ã®NDEF Recordãå«ã¾ããã
NDEF Message | |||
NDEF Record 0 | NDEF Record 1 | NDEF Record 2 | ... |
3ã¤ã®ã¢ã¼ã
- P2P: NFCã§ãã¤ã¹å士éä¿¡ããã¢ã¼ããã³ãã³ãéä¿¡å´ãã¤ãã·ã¨ã¼ã¿ãåä¿¡å´ãã¿ã¼ã²ãããAndroid Beam
- ãªã¼ã/ã©ã¤ã¿: NFCããã¤ã¹ãNFCã¿ã°ãããã¼ã¿ã®èªã¿æ¸ãããã¢ã¼ãã
- ã«ã¼ãã¨ãã¥ã¬ã¼ã·ã§ã³: NFCããã¤ã¹ãéæ¥è§¦ICã«ã¼ãã®å½¹å²ãããã¢ã¼ããAndroidã§ã¯æä¾ããã¦ããªãã
NFC Forum Tag
NFC Forumã§è¦å®ãã¦ããæä½é対å¿ããªããã°ãªããªã(NFCã¿ã°ã¨ãã¦ãã©ã¼ãããå¯è½ãª)ã¿ã°ã
Androidã§ã®NFCã®æ±ã
æä½éManifestãã¡ã¤ã«ã«è¨è¿°ããå¿ è¦ãããå 容
å¿ è¦ãªAPI Level ã¯10以ä¸. AAR(å¾è¿°)ã®æ¸ãè¾¼ã¿ã¯14以ä¸ã
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="17" />
NFCã使ãããã®ãã¼ããã·ã§ã³
<uses-permission android:name="android.permission.NFC" />
Play Store é ä¿¡æã«NFC対å¿ç«¯æ«ã§ããã¢ããªã表示ãããªãããã«ãããå ´åã¯æ¬¡ã®ããã«æ¸ãã
<uses-feature android:name="android.hardware.nfc" android:required="true"/>
ã¿ã°ãã¯ããã¸ã¼
NFCã¿ã°ãèªã¿åã£ãéã«ããã®ã¿ã°ã®è¦æ ¼ãªã©ã示ãæååã
- "NfcA"ãISO/IEC 14443 Type A æºæ ã®ã¿ã°
- "NfcB"ãISO/IEC 14443 Type B æºæ ã®ã¿ã°
- "NfcF"ãJIS 6319-4 æºæ ã®ã¿ã° (Felica)
- "NtcV"ãISO/IEC 15693 æºæ ã®ã¿ã° (Vã¯Vicinityã®ç¥?)
- "IsoDep"ãISO/IEC 14443ã§è¦å®ããã¦ãããã¼ã¿äº¤æå½¢å¼DEP(Data Exchange Protocol)ã§éä¿¡å¯è½ãªã¿ã°
- "MifareUltralight"ãNfcAã«åºã¥ããè¦æ ¼ã®ä¸ã¤ãä½éãç©ãã§ããã¡ã¢ãªãå°ãªãã
- "MifareClassic"ãNfcAã«åºã¥ããè¦æ ¼ã®ä¸ã¤ãã¡ã¢ãªãå¤ããâ»ãã£ãªã¢ããçºå£²ãã¦ããAndroid端æ«ã§ã¯èªã¿åããªãå ´åããããããã
- "Ndef"ãNDEFãã©ã¼ãããæ¸ã¿ã®ã¿ã°ããã®ã¿ã°ã¯NDEFãã¼ã¿ãå«ãã§ããã
- "NdefFormatable"ãNDEFãã©ã¼ãããå¯è½ãªã¿ã°ããã©ã¼ãããããã¨ã¿ã°ãã¯ããã¸ã¼ãNdefã«ãªãã
- "NfcBarcode"ãRFIDã¿ã°ã®ä¸ç¨®ãã¾ã æ®åãã¦ããªãã
ã¿ã°ãã£ã¹ãããã·ã¹ãã
NFCã¿ã°ããåãåã£ããã¼ã¿ã解æããã¢ããªã«é©åã«å¼ã渡ãä»çµã¿ã
èµ·åã¢ããªæ±ºå®ããã¼
- ç¾å¨ãã©ã¢ã°ã©ã¦ã³ãã«ããã¢ã¯ãã£ããã£ãåªå çã«ã¿ã°ãåãåãè¨å®ã«ãªã£ã¦ããå ´åããã®ã¢ã¯ãã£ããã£ã§å®£è¨ããã¦ãããã£ã«ã¿ã«å¾ããã¢ã¯ãã£ããã£ãèµ·åãã
- èªã¿åã£ãNFCã¿ã°ã«AAR(Android Application Record)ãå«ã¾ãã¦ãããã©ãããèªèãããå«ã¾ãã¦ããå ´åããã®ã¢ããªãèµ·åããã¢ããªãæªã¤ã³ã¹ãã¼ã«ãªããGoogle Playã§ãã®ã¢ããªãæ¤ç´¢ããã
- 端æ«ã«ã¤ã³ã¹ãã¼ã«ããã¦ããã¢ããªã®AndroidManifest.xmlã«ã¦å®ç¾©ãããã¢ã¯ãã£ããã£ã«è¨å®ããããã£ã«ã¿ã«å¾ããèµ·åã§ããã¢ã¯ãã£ããã£ã®ä¸è¦§ã表示ããã
NFCã¿ã°ãèªã¿è¾¼ã¾ããå¾ã®Intentã¢ã¯ã·ã§ã³
NFCã¿ã°ãèªã¿è¾¼ã¾ããã¨ã¿ã°ãã£ã¹ãããã·ã¹ãã ã¯æ¬¡ã®1,2,3ã®åªå
é ä½ã§NFCã¿ã°æ
å ±ãActivityã¸éã
- NDEF_DISCOVEREDã¢ã¯ã·ã§ã³(NDEF ãã©ã¼ãããæ¸ã¿)
- TECH_DISCOVEREDã¢ã¯ã·ã§ã³(æªç¥ã¾ãã¯NDEFãã©ã¼ãããããã¦ããªãã¿ã°)
- TAG_DISCOVEREDã¢ã¯ã·ã§ã³(ãããã«ãå½ã¦ã¯ã¾ããªã)
AndroidManifest.xmlã®ã¤ã³ãã³ããã£ã«ã¿
NDEF_DISCOVEREDã¢ã¯ã·ã§ã³ã®ã¤ã³ãã³ããã£ã«ã¿(API Level 10)
NDEF_DISCOVEREDã¢ã¯ã·ã§ã³ãåãåãå ´å
<intent-filter > <action android:name="android.nfc.action.NDEF_DISCOVERED" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter>
NDEFã«æå®ããMIMEã¿ã¤ããåå¨ããã°èªã¿åãå ´å
<intent-filter > <action android:name="android.nfc.action.NDEF_DISCOVERED" /> <category android:name="android.intent.category.DEFAULT" /> <data android:mimeType="text/plain" /> </intent-filter>
NDEFã«æå®ããã¹ãã¼ã ãåå¨ããã°èªã¿åãå ´å
<intent-filter > <action android:name="android.nfc.action.NDEF_DISCOVERED" /> <category android:name="android.intent.category.DEFAULT" /> <data android:scheme="http" /> <data android:scheme="https" /> </intent-filter>
TECH_DISCOVEREDã¢ã¯ã·ã§ã³ã®ã¤ã³ãã³ããã£ã«ã¿(API Level 10)
æå®ããTECHLISTã«è©²å½ããNFCãèªã¿åãå ´å
<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/filter_nfc" />
TECHLISTã®ä¾(res/xml/filter_nfc.xml)
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <tech-list> <tech>android.nfc.tech.NfcA</tech> <tech>android.nfc.tech.Ndef</tech> </tech-list> <tech-list> <tech>android.nfc.tech.NfcB</tech> <tech>android.nfc.tech.Ndef</tech> </tech-list> <tech-list> <tech>android.nfc.tech.NfcF</tech> <tech>android.nfc.tech.Ndef</tech> </tech-list> <tech-List> <tech>android.nfc.tech.NfcV</tech> <tech>android.nfc.tech.Ndef</tech> </tech-List> <tech-list> <tech>android.nfc.tech.NdefFormatable</tech> </tech-list> </resources>
TAG_DISCOVREDã¢ã¯ã·ã§ã³ã®ã¤ã³ãã³ããã£ã«ã¿(API Level 9)
ã¿ã°ãã¯ããã¸ã¼ã®ãªã¹ããæå®ãã¦ããã¢ããªãç¡ããã¾ãã¯æå®ãã¦ãã£ã¦ããããã«è©²å½ããªãå ´åã«ã
æ±ç¨çãªã¿ã°æ
å ±ãªã©ã確èªãããã¨ãã
ãã¾ã使ãæ©ä¼ã¯ç¡ãã
<intent-filter> <action android:name="android.nfc.action.TAG_DISCOVERED" /> </intent-filter>
NFCã¿ã°ã®æ¤ç¥
Androidã§ãNFCãæ±ãããã®ã¯ã©ã¹ãNfcAdapterãstatic ã¡ã½ããgetDefualtAdapter(Context context)ã§ã¤ã³ã¹ã¿ã³ã¹ã®çæãè¡ãã
ãã使ãã®ã§ãonCreate()ã§çæãã¦ã¡ã³ãå¤æ°ã§æã£ã¦ããã
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mNfcAdapter = NfcAdapter.getDefaultAdapter(this); //NFCãæ±ãããã®ã¤ã³ã¹ã¿ã³ã¹ãåå¾ setContentView(R.layout.activity_main); }
NFCãæå¹ã«ãªã£ã¦ãããã©ããã®ç¢ºèª
端æ«ã«NFCé対å¿ã®å ´åãNfcAdapter.getDefaultAdapter()ã®çµæãnullã«ãªãã
ã¾ã,NFCæ©è½ããªã³ã«ãªã£ã¦ãããã©ããã¯NfcAdapter#isEnabled()ã§ç¢ºãããã
private boolean hasNFC() { return mNfcAdapter != null; } private boolean isEnabledNFC() { return hasNFC() && mNfcAdapter.isEnabled(); }
NFCãOFFã«ãªã£ã¦ããã ããªããNFCã®è¨å®ç»é¢ãéãã¦ãããã¨è¦ªåã
String str = ""; if (!hasNFC()) str = "NFC not supported"; if (!isEnabledNFC()) { str = "Please enable NFC"; String setting = Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN ? Settings.ACTION_NFC_SETTINGS : Settings.ACTION_WIRELESS_SETTINGS; startActivity(new Intent(setting)); } if (!str.isEmpty()) Toast.makeText(this, str, Toast.LENGTH_SHORT).show();
â»æ³¨æãSettings.ACTION_NFC_SETTINGSã¯API Level 16以ä¸
ãã©ã¢ã°ã©ã¦ã³ããã£ã¹ããã
NFCã®æ¤ç¥ããã©ã¢ã°ã©ã¦ã³ãã«ããActivityãåªå
çã«å¦çããã(ç¡é§ã«ã¢ããªé¸æãé¢ã表示ãããªããã)ã«ã¯ããã©ã¢ã°ã©ã¦ã³ããã£ã¹ããããæå¹ã«ããã
æå¹ã«ããã«ã¯NfcAdapter.enableForegroundDispatch()ã¡ã½ããã使ç¨ãããé常onResume()ã§è¡ãã
NfcAdapter.enableForegroundDispatch(Activity activity, PendingIntent intent, IntentFilter[] filters, String[][] techLists)
- ã¿ã°ãã¹ãã£ã³ããæã«æåã«ã¤ã³ãã³ããã£ã«ã¿ã¼ã«ããããããããã§ãã¯
- ãããã¤ã³ãã³ããã£ã«ã¿ã¼ã«ããããã¦ããªããã°ãNfcAdapter.ACTION_TECH_DISCOVERED ã«ãã©ã¼ã«ããã¯ããã®ã§ã次ã«ãã¯ããã¸ã¼ãªã¹ãã«ããããããããã§ãã¯
ã¤ã³ãã³ããã£ã«ã¿ã¼ã¯ãNDEFãã©ã¼ãããããã¦ãã¦ãMIMEã¿ã¤ããæã¤ãã®ã«éããããURL ã SmartPoster ã¯MIMEã¿ã¤ããæããªããããã¤ã³ãã³ããã£ã«ã¿ã¼ã§ã¯ããããããNfcAdapter.ACTION_TECH_DISCOVERED ã«ãã©ã¼ã«ããã¯ãããã¾ããããããNDEFãã©ã¼ãããããã¦ããªããã°ãNfcAdapter.ACTION_TECH_DISCOVERED ã«ãã©ã¼ã«ããã¯ãããnullãæå®ããå ´åããã¯ããã¸ã¼ãªã¹ãã«ãããããã¿ã°å ¨ã¦ãåä¿¡ããã
次㫠ãã¯ããã¸ã¼ãªã¹ãã«ããããããããã§ãã¯ãããã nullãæå®ããå ´åãã¤ã³ãã³ããã£ã«ã¿ã«ãããããã¿ã°å ¨ã¦ãåä¿¡ããã
ã¤ã³ãã³ããã£ã«ã¿ã¨ãã¯ããã¸ã¼ãªã¹ãå ±ã«nullãªãå ¨ã¦ã®ã¿ã°ãåä¿¡ããã
ãã©ã¢ã°ã©ã¦ã³ããã£ã¹ããããç¡å¹ã«ããã«ã¯ãNfcAdapter.disableDispatch(Activity activity)ã¡ã½ããã使ç¨ããã
é常ãonPause()ã§è¨è¿°ããActivityãããã¯ã°ã©ã¦ã³ãã«åã£ãéã¯ãåªå
çã«åããã®ããããã
@Override protected void onResume() { super.onResume(); //Handle all of our received NFC intents in this activity. if (mNfcAdapter != null) { Intent intent = new Intent(this, this.getClass()).setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); mNfcPendingIntent = PendingIntent.getActivity(this, 0, intent, 0); /** filters */ IntentFilter actionNdef = IntentFilter.create(NfcAdapter.ACTION_NDEF_DISCOVERED, "*/*"); //= IntentFilter.create(NfcAdapter.ACTION_NDEF_DISCOVERED, "image/png"); IntentFilter[] filters //= null; //ã¿ã°å é¨ã®ãã¼ã¿ãå¶éããªãå ´å = new IntentFilter[] { actionNdef }; /** techList */ String[][] techLists //= null; //ã¿ã°ã®ç¨®é¡ãå¶éããªãå ´å = new String[][] { new String[] { NfcA.class.getName() }, new String[] { NfcB.class.getName() }, new String[] { NfcF.class.getName() }, new String[] { NfcV.class.getName() }, }; mNfcAdapter.enableForegroundDispatch(this, mNfcPendingIntent, filters, techLists); } } @Override protected void onPause() { super.onPause(); //Activityãããã¯ã°ã©ã¦ã³ãã«åã£ãéã¯ãåªå çã«åãåãã®ãããã if (mNfcAdapter != null) mNfcAdapter.disableForegroundDispatch(this); }
NFCã¤ã³ãã³ãã®æ¤ç¥
onNewIntent()ã§NFCã¿ã°ã®æ å ±ãå«ãã ã¤ã³ãã³ããåä¿¡ããããã ããNFCã®ã¤ã³ãã³ã以å¤ãåä¿¡ããã®ã§ãNFCã¢ã¯ã·ã§ã³ãã©ããã確èªããã
@Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); String action = intent.getAction(); if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(action) || //NDEFãã©ã¼ãããæ¸ã¿ NfcAdapter.ACTION_TECH_DISCOVERED.equals(action) || //æªç¥ãããã¯NDEFãã©ã¼ãããããã¦ããªã ååæ¸ãè¾¼ã¿æã«ã¯å¿ è¦? NfcAdapter.ACTION_TAG_DISCOVERED.equals(action)) { //ãã以å¤ã
UIDã®åå¾
intent.getByteArrayExtra(NfcAdapter.EXTRA_ID)ã§åå¾ã
StringBuilder sb = new StringBuilder(); //NFC-UIDåå¾ byte[] uid = intent.getByteArrayExtra(NfcAdapter.EXTRA_ID); if (uid != null) for (byte id: uid) sb.append(String.format("%02x", id & 0xff));
ã¿ã°æ
å ±ã®åå¾
intent.getParcelableExtra(NfcAdapter.EXTRA_TAG)ã§åå¾ã
public static String[] getTechList(Intent intent) { Tag tag = (Tag) intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); return tag != null ? tag.getTechList() : new String[0]; }
NdefMessageã®åå¾
intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES)ã§åå¾ã
â»æ³¨æ é
åã®å½¢ã§è¿ã£ã¦ãããé常ãNdefMessageã¯ï¼ã¤ãªã®ã§ä¸çªç®ã®è¦ç´ ãè¦ãã
public static NdefMessage getNdefMessage(Intent intent) { Parcelable[] raws = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES); return raws == null || raws.length == 0 ? null : (NdefMessage)raws[0]; } public static NdefMessage[] getNdefMessages(Intent intent) { Parcelable[] raws = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES); if (raws == null) return new NdefMessage[0]; NdefMessage[] msgs = new NdefMessage[raws.length]; for (int i = 0; i < raws.length; ++i) msgs[i] = (NdefMessage) raws[i]; return msgs; }
NdefRecordã®åå¾
NdefMessage.getRecords()ã§NdefRecordãåå¾
NdefRecordã¯ã©ã¹ã«ã¯ãID(byte), Payload(byte), Tnf(short), Type(byte)ã®ã²ãã¿ã¡ã½ãããããã
byte⇄Stringã®å¤æã¯âã§è¡ãããAndroidã§ã¯DefaultCharsetãUTF-8ãªã®ã§ãCharset.forName("UTF-8")ã¯çç¥ãã¦ãããã¯ããä»ã®Charsetã使ãå ´åã¯ã¡ããã¨æå®ããã
byte[] bytes = str.getBytes(Charset.forName("UTF-8")); //String -> byte[] String str = new String(bytes, Charset.forName("UTF-8")); //byte[] -> String
byte[]ã16é²è¡¨ç¤ºã«ããããªãâã¿ãããªæãã
javaã«unsignedã追å ãããæ¥ã¯æ¥ãã®ã ããã...
public static String bytesToString(byte[] byteArray) { StringBuilder sb = new StringBuilder(); for (byte b: byteArray) sb.append(String.format("%02x", b & 0xff)); return sb.toString(); }
NDEFã®ä½ãæ¹ããã¼ã¹ã®ä»æ¹ã¯ã¾ãä»åº¦