ブログ記事
で使ってる NFC 読み取りサンプルの Gist
書籍『NFC Hacks』(株式会社ブリリアントサービス著, オライリージャパン発行)の Hack #32 を参考にして作成
ブログ記事
で使ってる NFC 読み取りサンプルの Gist
書籍『NFC Hacks』(株式会社ブリリアントサービス著, オライリージャパン発行)の Hack #32 を参考にして作成
<?xml version="1.0" encoding="utf-8"?> | |
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" | |
xmlns:app="http://schemas.android.com/apk/res-auto" | |
xmlns:tools="http://schemas.android.com/tools" | |
android:layout_width="match_parent" | |
android:layout_height="match_parent" | |
tools:context=".MainActivity"> | |
<TextView | |
android:id="@+id/tvInfo" | |
android:layout_width="match_parent" | |
android:layout_height="wrap_content" | |
android:textAppearance="?android:attr/textAppearanceLarge" | |
android:text="Hello World!" | |
app:layout_constraintBottom_toBottomOf="parent" | |
app:layout_constraintLeft_toLeftOf="parent" | |
app:layout_constraintRight_toRightOf="parent" | |
app:layout_constraintTop_toTopOf="parent" /> | |
</androidx.constraintlayout.widget.ConstraintLayout> |
<?xml version="1.0" encoding="utf-8"?> | |
<manifest xmlns:android="http://schemas.android.com/apk/res/android" | |
package="com.example.nfcreaderexample"> | |
<uses-permission android:name="android.permission.NFC" /> | |
<application | |
android:allowBackup="true" | |
android:icon="@mipmap/ic_launcher" | |
android:label="@string/app_name" | |
android:roundIcon="@mipmap/ic_launcher_round" | |
android:supportsRtl="true" | |
android:theme="@style/AppTheme"> | |
<activity | |
android:name=".MainActivity" | |
android:launchMode="singleTask"> | |
<intent-filter> | |
<action android:name="android.intent.action.MAIN" /> | |
<category android:name="android.intent.category.LAUNCHER" /> | |
</intent-filter> | |
<!-- | |
<intent-filter> | |
<action android:name="android.nfc.action.NDEF_DISCOVERED" /> | |
<category android:name="android.intent.category.DEFAULT" /> | |
<data android:mimeType="image/jpeg" /> | |
</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_filter" /> | |
<intent-filter> | |
<action android:name="android.nfc.action.TAG_DISCOVERED" /> | |
<category android:name="android.intent.category.DEFAULT" /> | |
</intent-filter> | |
--> | |
</activity> | |
</application> | |
</manifest> |
package com.example.nfcreaderexample; | |
import androidx.appcompat.app.AppCompatActivity; | |
import android.app.PendingIntent; | |
import android.content.Intent; | |
import android.content.IntentFilter; | |
import android.nfc.FormatException; | |
import android.nfc.NdefMessage; | |
import android.nfc.NdefRecord; | |
import android.nfc.NfcAdapter; | |
import android.nfc.Tag; | |
import android.nfc.tech.Ndef; | |
import android.nfc.tech.TagTechnology; | |
import android.os.Bundle; | |
import android.os.Parcelable; | |
import android.util.Log; | |
import android.widget.TextView; | |
import java.io.IOException; | |
import java.util.Arrays; | |
import java.util.List; | |
/** | |
* 書籍 NFC Hacks の Hack #32 を参考に作成した、 | |
* NFC読み込みアプリのサンプル実装 | |
*/ | |
public class MainActivity extends AppCompatActivity { | |
private final String TAG = MainActivity.class.getSimpleName(); | |
private NfcAdapter mNfcAdapter; | |
@Override | |
protected void onCreate(Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
setContentView(R.layout.activity_main); | |
Log.d(TAG, "onCreate"); | |
mNfcAdapter = NfcAdapter.getDefaultAdapter(this); | |
Intent intent = this.getIntent(); | |
analyze(intent); | |
} | |
@Override | |
protected void onPause() { | |
super.onPause(); | |
mNfcAdapter.disableForegroundDispatch(this); | |
} | |
@Override | |
protected void onNewIntent(Intent intent) { | |
super.onNewIntent(intent); | |
Log.d(TAG, "onNewIntent"); | |
analyze(intent); | |
} | |
private void analyze(Intent intent) { | |
if (intent == null) { | |
Log.d(TAG, "analyze: no intent"); | |
return; | |
} | |
if (intent.getAction().equals(NfcAdapter.ACTION_NDEF_DISCOVERED)) { | |
StringBuilder sb = new StringBuilder(); | |
sb.append("ACTION_NDEF_DISCOVERED\n"); | |
getNdefInfo(intent, sb); | |
((TextView) findViewById(R.id.tvInfo)).setText(new String(sb)); | |
} else if (intent.getAction().equals(NfcAdapter.ACTION_TECH_DISCOVERED)) { | |
StringBuilder sb = new StringBuilder(); | |
sb.append("ACTION_TECH_DISCOVERED\n"); | |
getTechInfo(intent, sb); | |
((TextView) findViewById(R.id.tvInfo)).setText(new String(sb)); | |
} else if (intent.getAction().equals(NfcAdapter.ACTION_TAG_DISCOVERED)) { | |
StringBuilder sb = new StringBuilder(); | |
sb.append("ACTION_TAG_DISCOVERED\n"); | |
getTechInfo(intent, sb); | |
((TextView) findViewById(R.id.tvInfo)).setText(new String(sb)); | |
} | |
} | |
@Override | |
protected void onResume() { | |
super.onResume(); | |
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, getClass()), 0); | |
IntentFilter ndefFilter = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED); | |
IntentFilter techFilter = new IntentFilter(NfcAdapter.ACTION_TECH_DISCOVERED); | |
IntentFilter tagFilter = new IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED); | |
// NDEF_DISCOVERED, text/plain に対応 | |
try { | |
ndefFilter.addDataType("text/plain"); | |
} catch (IntentFilter.MalformedMimeTypeException e) { | |
e.printStackTrace(); | |
} | |
IntentFilter[] intentFilters = new IntentFilter[] {ndefFilter, techFilter, tagFilter}; | |
// TECH_DISCOVERED, NDEF を指定 | |
String tech = Ndef.class.getName(); | |
String techlist[] = new String[]{tech}; // and 条件 | |
String techLists[][] = new String[][] {techlist}; // or 条件 | |
// すべてを受け付ける | |
//mNfcAdapter.enableForegroundDispatch(this, pendingIntent, null, null); | |
// ACTION_TECH_DISCOVERED 用に tech list を指定 | |
mNfcAdapter.enableForegroundDispatch(this, pendingIntent, intentFilters, techLists); | |
} | |
private void getNdefInfo(Intent intent, StringBuilder sb) { | |
getTagInfo(intent, sb); | |
NdefMessage[] msgs = null; | |
Parcelable[] rawMsgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES); | |
if (rawMsgs != null) { | |
msgs = new NdefMessage[rawMsgs.length]; | |
for (int i = 0; i < rawMsgs.length; i++) { | |
msgs[i] = (NdefMessage) rawMsgs[i]; | |
} | |
} | |
if (msgs != null) { | |
sb.append("NDEF INFO\n"); | |
for (int i = 0; i < msgs.length; i++) { | |
sb.append("message #:"); | |
sb.append(i); | |
sb.append("\n"); | |
NdefRecord[] records = msgs[i].getRecords(); | |
for (int j = 0; j < records.length; j++) { | |
sb.append("record #:"); | |
sb.append(j); | |
sb.append("\n"); | |
parseNdefRecord(records[j], sb); | |
} | |
sb.append("\n"); | |
} | |
} | |
} | |
private void parseNdefRecord(NdefRecord record, StringBuilder sb) { | |
sb.append(" record id:"); | |
sb.append(new String(record.getId())); // byte配列 -> String | |
sb.append("\n"); | |
sb.append(" tnf:"); | |
switch (record.getTnf()) { | |
case NdefRecord.TNF_EMPTY: | |
sb.append("TNF_EMPTY"); | |
break; | |
case NdefRecord.TNF_WELL_KNOWN: | |
sb.append("TNF_WELL_KNOWN"); | |
break; | |
case NdefRecord.TNF_MIME_MEDIA: | |
sb.append("TNF_MIME_MEDIA"); | |
break; | |
case NdefRecord.TNF_ABSOLUTE_URI: | |
sb.append("TNF_ABSOLUTE_URI"); | |
break; | |
case NdefRecord.TNF_EXTERNAL_TYPE: | |
sb.append("TNF_EXTERNAL_TYPE"); | |
break; | |
case NdefRecord.TNF_UNKNOWN: | |
sb.append("TNF_UNKOWN"); | |
break; | |
case NdefRecord.TNF_UNCHANGED: | |
sb.append("TNF_UNCHANGED"); | |
break; | |
} | |
sb.append("\n"); | |
sb.append(" type:"); | |
sb.append(new String(record.getType())); | |
sb.append("\n"); | |
sb.append(" payload:"); | |
sb.append(new String(record.getPayload())); | |
sb.append("\n"); | |
} | |
private void getTechInfo(Intent intent, StringBuilder sb) { | |
getTagInfo(intent, sb); | |
Tag tag = null; | |
tag = (Tag) intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); | |
if (tag != null) { | |
List<String> techList = Arrays.asList(tag.getTechList()); | |
if (techList.contains(Ndef.class.getName())) { | |
sb.append("TECH NDEF INFO\n"); | |
Ndef ndef = Ndef.get(tag); | |
sb.append(" tag type:"); | |
sb.append(ndef.getType()); | |
sb.append("\n"); | |
sb.append(" max size:"); | |
sb.append(ndef.getMaxSize()); | |
sb.append("\n"); | |
try { | |
NdefMessage msg = null; | |
ndef.connect(); | |
msg = ndef.getNdefMessage(); | |
if (msg != null) { | |
NdefRecord records[] = msg.getRecords(); | |
for (int j = 0; j < records.length; j++) { | |
sb.append("record #:"); | |
sb.append(j); | |
parseNdefRecord(records[j], sb); | |
} | |
sb.append("\n"); | |
} else { | |
sb.append("msg is null\n"); | |
} | |
} catch (FormatException e) { | |
e.printStackTrace(); | |
} catch (IOException e) { | |
e.printStackTrace(); | |
} finally { | |
try { | |
ndef.close(); | |
} catch (IOException e) { | |
e.printStackTrace(); | |
} | |
} | |
} | |
} | |
} | |
private void getTagInfo(Intent intent, StringBuilder sb) { | |
sb.append("TAG INFO\n"); | |
Tag tag = null; | |
tag = (Tag) intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); | |
if (tag != null) { | |
sb.append(" id:"); | |
setIdFromBytes(tag.getId(), sb); | |
sb.append("\n"); | |
String[] techList = tag.getTechList(); | |
if (techList != null) { | |
sb.append("tech list:\n"); | |
for (int i = 0; i < techList.length; i++) { | |
sb.append(techList[i]); | |
sb.append("\n"); | |
} | |
} | |
} | |
} | |
private void setIdFromBytes(byte[] bytes, StringBuilder sb) { | |
for (byte b: bytes) { | |
sb.append(String.format("%02x", b)); | |
} | |
} | |
} |
<?xml version="1.0" encoding="utf-8"?> | |
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> | |
<tech-list> | |
<!-- | |
<tech>android.nfc.IsoDep</tech> | |
<tech>android.nfc.tech.MifareClassic</tech> | |
<tech>android.nfc.tech.MifareUltralight</tech> | |
--> | |
<tech>android.nfc.tech.Ndef</tech> | |
<!-- | |
<tech>android.nfc.tech.NdefFormatable</tech> | |
<tech>android.nfc.tech.NfcA</tech> | |
<tech>android.nfc.tech.NfcB</tech> | |
<tech>android.nfc.tech.NfcBarcode</tech> | |
<tech>android.nfc.tech.NfcF</tech> | |
<tech>android.nfc.tech.NfcV</tech> | |
--> | |
</tech-list> | |
</resources> |