Membaca Tag NFC Dengan Android

Apakah Anda ingin tahu tentang apa itu NFC dan bagaimana itu dapat diintegrasikan ke dalam aplikasi Android Anda sendiri? Tutorial ini akan segera memperkenalkan Anda ke topiknya sebelum menyelam dan mengajarkan Anda cara membuat aplikasi pembaca NFC sederhana!

Apa itu NFC?
NFC adalah singkatan untuk Near Field Communication. Ini adalah standar internasional untuk pertukaran data tanpa kontak. Berbeda dengan berbagai macam teknologi lainnya, seperti LAN nirkabel dan Bluetooth, jarak maksimum kedua perangkat adalah 10cm. Pengembangan standar dimulai pada tahun 2002 oleh NXP Semiconductors dan Sony. Forum NFC, sebuah konsorsium lebih dari 170 perusahaan dan anggota, termasuk Mastercard, NXP, Nokia, Samsung, Intel, dan Google, telah merancang spesifikasi baru sejak 2004.

Ada berbagai kemungkinan untuk penggunaan NFC dengan perangkat mobile; misalnya, tiket tanpa kertas, kontrol akses, pembayaran tanpa uang tunai, dan kunci mobil. Dengan bantuan tag NFC Anda dapat mengontrol ponsel Anda dan mengubah pengaturan. Data dapat ditukarkan hanya dengan memegang kedua perangkat di samping satu sama lain.

Dalam tutorial ini saya ingin menjelaskan cara menerapkan NFC dengan SDK Android, perangkap apa yang ada, dan apa yang harus diingat. Kita akan membuat aplikasi langkah demi langkah, yang dapat membaca isi dari tag NFC yang mendukung NDEF.

Teknologi NFC
Ada berbagai tag NFC yang bisa dibaca dengan smartphone. Spektrum berkisar dari stiker sederhana dan gantungan kunci hingga kartu yang rumit dengan perangkat keras kriptografi terintegrasi. Tag-tag juga berbeda dalam teknologi chip mereka. Yang paling penting adalah NDEF, yang didukung oleh sebagian besar tag. Selain itu, Mifare harus disebutkan karena ini adalah teknologi chip tanpa kontak yang paling banyak digunakan di seluruh dunia. Beberapa tag dapat dibaca dan ditulis, sementara yang lain hanya bisa dibaca atau dienkripsi.

Hanya NFC Data Exchange Format (NDEF) yang dibahas dalam tutorial ini.

Menambahkan Dukungan NFC di sebuah Aplikasi
Kita mulai dengan proyek baru dan activity kosong. Penting untuk memilih versi SDK minimum level 10, karena NFC hanya didukung setelah Android 2.3.3. Ingat untuk memilih nama paket Anda sendiri. Saya telah memilih net.vrallev.android.nfc.demo, karena vrallev.net adalah domain dari situs web saya dan bagian lain mengacu pada topik aplikasi ini.

Layout default yang dihasilkan oleh Eclipse hampir cukup bagi kita. Saya hanya menambahkan ID ke TextView dan mengubah teksnya.

Untuk mendapatkan akses ke perangkat keras NFC, Anda harus meminta izin dalam manifest. Jika aplikasi tidak berfungsi tanpa NFC, Anda dapat menetapkan ketentuan dengan tag uses-feature. Jika NFC diperlukan, aplikasi tidak dapat dipasang di perangkat tanpanya dan Google Play hanya akan menampilkan aplikasi Anda kepada pengguna yang memiliki perangkat NFC.

MainActivity seharusnya hanya terdiri dari metode onCreate(). Anda dapat berinteraksi dengan perangkat keras melalui kelas NfcAdapter. Penting untuk mengetahui apakah NfcAdapter adalah null. Dalam hal ini, perangkat Android tidak mendukung NFC.

package net.vrallev.android.nfc.demo;
import android.app.Activity;
import android.nfc.NfcAdapter;
import android.os.Bundle;
import android.widget.TextView;
import android.widget.Toast;
/**
* Activity for reading data from an NDEF Tag.
*
* @author Ralf Wondratschek
*
*/
public class MainActivity extends Activity {
public static final String TAG = “NfcDemo”;
private TextView mTextView;
private NfcAdapter mNfcAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); mTextView = (TextView) findViewById(R.id.textView_explanation); mNfcAdapter = NfcAdapter.getDefaultAdapter(this); if (mNfcAdapter == null) { // Stop here, we definitely need NFC Toast.makeText(this, “This device doesn’t support NFC.”, Toast.LENGTH_LONG).show(); finish(); return; } if (!mNfcAdapter.isEnabled()) { mTextView.setText(“NFC is disabled.”);
} else { mTextView.setText(R.string.explanation);
} handleIntent(getIntent());
}
private void handleIntent(Intent intent) {
// TODO: handle Intent
}
}

Jika kita memulai aplikasi kita sekarang, kita dapat melihat teks apakah NFC diaktifkan atau dinonaktifkan.

Cara Menyaring Tag NFC
Kita memiliki aplikasi contoh kita dan ingin menerima pemberitahuan dari sistem ketika kita melampirkan tag NFC ke perangkat. Seperti biasa, Android menggunakan sistem Intent untuk mengirim tag-tag ke aplikasi. Jika beberapa aplikasi dapat menangani Intent, pemilih activity akan ditampilkan dan pengguna dapat memutuskan aplikasi mana yang akan dibuka. Membuka URL atau berbagi informasi ditangani dengan cara yang sama.

Filter Intent NFC
Ada tiga filter berbeda untuk tag-tag:

1. ACTION_NDEF_DISCOVERED
2. ACTION_TECH_DISCOVERED
3. ACTION_TAG_DISCOVERED

Daftar ini diurutkan dari prioritas tertinggi hingga terendah.

Sekarang apa yang terjadi ketika sebuah tag terpasang ke smartphone? Jika sistem mendeteksi tag dengan dukungan NDEF, sebuah Intent dipicu. Intent ACTION_TECH_DISCOVERED dipicu jika tidak ada Activity dari aplikasi apa pun yang terdaftar untuk Intent NDEF atau jika tag tidak mendukung NDEF. Jika lagi tidak ada aplikasi yang ditemukan untuk Intent atau teknologi chip tidak dapat dideteksi, maka Intent ACTION_TAG_DISCOVERED akan diaktifkan. Gambar berikut menunjukkan prosesnya:

Singkatnya ini berarti bahwa setiap aplikasi perlu menyaring Intent dengan prioritas tertinggi. Dalam kasus kita, ini adalah Intent NDEF. Kita menerapkan Intent ACTION_TECH_DISCOVERED terlebih dahulu untuk menyoroti perbedaan antara prioritas.

Tech Discovered Intent
Kita harus menentukan teknologi yang kita minati. Untuk tujuan ini, kita membuat subfolder bernama xml di folder res. Dalam folder ini kita membuat file nfc_tech_filter.xml, di mana kita menentukan teknologinya. android.nfc.tech.Ndef
Sekarang kita harus membuat IntentFilter di manifest, dan aplikasi akan dimulai ketika kita memasang tag.

Jika tidak ada aplikasi lain yang terdaftar untuk Intent ini, Activity kita akan segera dimulai. Namun, di perangkat saya, aplikasi lain dipasang, sehingga pemilih activity ditampilkan.

NDEF Discovered Intent
Seperti yang saya sebutkan sebelumnya, Tech Discovered Intent memiliki prioritas tertinggi kedua. Namun, karena aplikasi kita hanya akan mendukung NDEF, kita dapat menggunakan NDEF Discovered Intent sebagai gantinya, yang memiliki prioritas lebih tinggi. Kita dapat menghapus daftar teknologi lagi dan mengganti IntentFilter dengan yang berikut.

Saat kita melampirkan tag-nya sekarang, aplikasi akan dimulai seperti sebelumnya. Namun, ada perbedaan bagi saya. Pemilih activity tidak muncul dan aplikasi segera dimulai, karena Intent NDEF memiliki prioritas lebih tinggi dan aplikasi lain hanya terdaftar untuk prioritas yang lebih rendah. Itulah yang kita inginkan.

Foreground Dispatch
Perhatikan bahwa satu masalah tetap ada. Ketika aplikasi kita sudah dibuka dan kita melampirkan lagi tag itu, aplikasi dibuka untuk kedua kalinya daripada mengirimkan tag-nya secara langsung. Ini bukan perilaku yang dimaksudkan. Anda dapat melewati masalahnya dengan menggunakan Foreground Dispatch.

Alih-alih sistem setelah mendistribusikan Intent, Anda dapat mendaftarkan Activity Anda untuk menerima tag secara langsung. Ini penting untuk alur kerja tertentu, di mana tidak masuk akal untuk membuka aplikasi lain.

Saya telah memasukkan penjelasan di tempat yang sesuai dalam kodenya.

package net.vrallev.android.nfc.demo;
import android.app.Activity;
import android.app.PendingIntent;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentFilter.MalformedMimeTypeException;
import android.nfc.NfcAdapter;
import android.os.Bundle;
import android.widget.TextView;
import android.widget.Toast;
/**
* Activity for reading data from an NDEF Tag.
*
* @author Ralf Wondratschek
*
*/
public class MainActivity extends Activity {
public static final String MIME_TEXT_PLAIN = “text/plain”;
public static final String TAG = “NfcDemo”;
private TextView mTextView;
private NfcAdapter mNfcAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); mTextView = (TextView) findViewById(R.id.textView_explanation); mNfcAdapter = NfcAdapter.getDefaultAdapter(this); if (mNfcAdapter == null) { // Stop here, we definitely need NFC Toast.makeText(this, “This device doesn’t support NFC.”, Toast.LENGTH_LONG).show(); finish(); return; } if (!mNfcAdapter.isEnabled()) { mTextView.setText(“NFC is disabled.”);
} else { mTextView.setText(R.string.explanation);
} handleIntent(getIntent());
}
@Override
protected void onResume() {
super.onResume(); /** * It’s important, that the activity is in the foreground (resumed). Otherwise * an IllegalStateException is thrown. */
setupForegroundDispatch(this, mNfcAdapter);
}
@Override
protected void onPause() {
/** * Call this before onPause, otherwise an IllegalArgumentException is thrown as well. */
stopForegroundDispatch(this, mNfcAdapter); super.onPause();
}
@Override
protected void onNewIntent(Intent intent) { /** * This method gets called, when a new Intent gets associated with the current activity instance. * Instead of creating a new activity, onNewIntent will be called. For more information have a look * at the documentation. * * In our case this method gets called, when the user attaches a Tag to the device. */
handleIntent(intent);
}
private void handleIntent(Intent intent) {
// TODO: handle Intent
}
/**
* @param activity The corresponding {@link Activity} requesting the foreground dispatch.
* @param adapter The {@link NfcAdapter} used for the foreground dispatch.
*/
public static void setupForegroundDispatch(final Activity activity, NfcAdapter adapter) {
final Intent intent = new Intent(activity.getApplicationContext(), activity.getClass());
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); final PendingIntent pendingIntent = PendingIntent.getActivity(activity.getApplicationContext(), 0, intent, 0); IntentFilter[] filters = new IntentFilter[1];
String[][] techList = new String[][]{}; // Notice that this is the same filter as in our manifest.
filters[0] = new IntentFilter();
filters[0].addAction(NfcAdapter.ACTION_NDEF_DISCOVERED);
filters[0].addCategory(Intent.CATEGORY_DEFAULT);
try { filters[0].addDataType(MIME_TEXT_PLAIN);
} catch (MalformedMimeTypeException e) { throw new RuntimeException(“Check your mime type.”);
} adapter.enableForegroundDispatch(activity, pendingIntent, filters, techList);
}
/**
* @param activity The corresponding {@link BaseActivity} requesting to stop the foreground dispatch.
* @param adapter The {@link NfcAdapter} used for the foreground dispatch.
*/
public static void stopForegroundDispatch(final Activity activity, NfcAdapter adapter) {
adapter.disableForegroundDispatch(activity);
}
}

Sekarang, ketika Anda melampirkan sebuah tag dan aplikasi kita sudah dibuka, onNewIntent dipanggil dan tidak ada Activity baru yang dibuat.

Membaca Data dari sebuah Tag NDEF
Langkah terakhir adalah membaca data dari tag. Penjelasannya disisipkan di tempat yang tepat dalam kode sekali lagi. NdefReaderTask adalah kelas private bagian dalam.

package net.vrallev.android.nfc.demo;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
import android.app.Activity;
import android.app.PendingIntent;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentFilter.MalformedMimeTypeException;
import android.nfc.NdefMessage;
import android.nfc.NdefRecord;
import android.nfc.NfcAdapter;
import android.nfc.Tag;
import android.nfc.tech.Ndef;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
import android.widget.Toast;
/*
* … other code parts
*/
private void handleIntent(Intent intent) {
String action = intent.getAction();
if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(action)) { String type = intent.getType();
if (MIME_TEXT_PLAIN.equals(type)) { Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); new NdefReaderTask().execute(tag); } else { Log.d(TAG, “Wrong mime type: ” + type);
}
} else if (NfcAdapter.ACTION_TECH_DISCOVERED.equals(action)) { // In case we would still use the Tech Discovered Intent
Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
String[] techList = tag.getTechList();
String searchedTech = Ndef.class.getName(); for (String tech : techList) { if (searchedTech.equals(tech)) { new NdefReaderTask().execute(tag); break; }
}
}
}

/**
* Background task for reading the data. Do not block the UI thread while reading.
*
* @author Ralf Wondratschek
*
*/
private class NdefReaderTask extends AsyncTask {
@Override
protected String doInBackground(Tag… params) {
Tag tag = params[0]; Ndef ndef = Ndef.get(tag);
if (ndef == null) { // NDEF is not supported by this Tag. return null;
} NdefMessage ndefMessage = ndef.getCachedNdefMessage(); NdefRecord[] records = ndefMessage.getRecords();
for (NdefRecord ndefRecord : records) { if (ndefRecord.getTnf() == NdefRecord.TNF_WELL_KNOWN && Arrays.equals(ndefRecord.getType(), NdefRecord.RTD_TEXT)) { try { return readText(ndefRecord); } catch (UnsupportedEncodingException e) { Log.e(TAG, “Unsupported Encoding”, e); } }
} return null;
}
private String readText(NdefRecord record) throws UnsupportedEncodingException {
/* * See NFC forum specification for “Text Record Type Definition” at 3.2. * * -forum.org/specs/ * * bit_7 defines encoding * bit_6 reserved for future use, must be * bit_5..0 length of IANA language code */ byte[] payload = record.getPayload(); // Get the Text Encoding
String textEncoding = ((payload[0] & 128) == 0) ? “UTF-8” : “UTF-16”; // Get the Language Code
int languageCodeLength = payload[0] & 0063; // String languageCode = new String(payload, 1, languageCodeLength, “US-ASCII”);
// e.g. “en” // Get the Text
return new String(payload, languageCodeLength + 1, payload.length – languageCodeLength – 1, textEncoding);
}
@Override
protected void onPostExecute(String result) {
if (result != null) { mTextView.setText(“Read content: ” + result);
}
}
}

Aplikasi ini sekarang berhasil membaca konten.

Aplikasi Berguna
Untuk memeriksa apakah data dibaca dan ditulis dengan benar, saya pribadi suka menggunakan aplikasi berikut:

* NFC TagInfo oleh NFC Research Lab untuk membaca data
* TagInfo oleh NXP SEMICONDUCTORS untuk membaca data
* TagWriter oleh NXP SEMICONDUCTORS untuk menulis data

Kesimpulan
Dalam tutorial ini saya telah menunjukkan kepada Anda bagaimana data dari tag NDEF dapat diekstrak. Anda bisa memperluas contoh ke jenis-jenis mime dan teknologi chip lainnya; sebuah fitur untuk menulis data akan berguna juga. Langkah pertama untuk bekerja dengan NFC dibuat. Namun, SDK Android menawarkan lebih banyak kemungkinan, seperti pertukaran data yang mudah (disebut Android Beam).

Tentang Penulis
Ralf Wondratschek adalah seorang mahasiswa ilmu komputer dari Jerman. Selain studinya, Ralf bekerja sebagai freelancer di bidang komputasi mobile. Dalam beberapa tahun terakhir ia telah bekerja dengan Java, XML, HTML, JSP, JSF, Eclipse, Google App Engine, dan tentu saja Android. Dia telah menerbitkan dua aplikasi Android hingga saat ini yang dapat ditemukan di sini.

Anda dapat mengetahui lebih lanjut tentang karya penulis di beranda vrallev.net.

Sumber-sumber
-forum.org/home/n-mark.jpg

/wiki/File%3A%C3%9Cberlagert.jpg

/images/nfc_tag_dispatch.png