Skip to content

Instantly share code, notes, and snippets.

@junichim
Last active July 11, 2023 08:39
Show Gist options
  • Save junichim/198bac2d9039da08a184bbc22c047795 to your computer and use it in GitHub Desktop.
Save junichim/198bac2d9039da08a184bbc22c047795 to your computer and use it in GitHub Desktop.
NFC 読み取りサンプル

ブログ記事

【Android】 NFC を試しました

で使ってる 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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment