آموزش خواندن و نوشتن NFC Tag در برنامه نویسی اندروید
سلام دوستان امیدوارم حالتان خوب باشد در این سری از آموزش برنامه نویسی اندروید به آموزش خواندن و نوشتن NFC Tag در برنامه نویسی اندروید می پردازیم قبلتر آموزشی کلی در این رابطه قرار داده بودیم که به صورت کلی Nfc Tag را مورد تشریح و استفاده قرار دادیم در این آموزش به خواندن و نوشتن Nfc Tag خواهیم پرداخت در ادمه با ما همراه باشید.
موارد مورد استفاده در Nfc Tag چیست ؟
به طور کلی برای نوشتن و دریافت مقدار دادی بسیار کم مثل url یا اعداد
برای اجرای برنامه ی خاص
برای باز کردن قفل (مورد استفاده در مترو)
یک کلید امنیتی برای یک اپلیکیشن
ابتدا Nfc گوشی خود را روشن کنید !
برای کار کردن با Nfc لازم است تا دسترسی آن را به AndroidManifest.xml اضافه کنید.
1 | <uses-permission android:name="android.permission.NFC" /> |
باید وارد فایل Build.gradle شده و آن را به شکل زیر تغییر دهید چون از متودهای Lambda جاوا 8 استفاده می کنیم باید حتما تغییر کند.
جاهایی که باید اضافه کنید با تگ here مشخص شده است.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | apply plugin: 'com.android.application' android { compileSdkVersion 25 buildToolsVersion "25.0.0" defaultConfig { applicationId "ir.programchi" minSdkVersion 19 targetSdkVersion 25 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" //here jackOptions { enabled true } } //here compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { exclude group: 'com.android.support', module: 'support-annotations' }) compile 'com.android.support:appcompat-v7:25.0.0' testCompile 'junit:junit:4.12' } |
بروی دکمه sync کلیک کنید.
وارد فایل String.xml شده و کدهای زیر را قرار دهید.
1 2 3 4 5 6 7 8 9 10 11 | <resources> <string name="app_name">NFC</string> <string name="message_write_error">Error Writing Message !</string> <string name="message_write_success">Successfully written to Tag !</string> <string name="message_write_progress">Writing to Tag..</string> <string name="message_tag_detected">NFC Tag Detected !</string> <string name="message_read_tag">Read from NFC Tag</string> <string name="message_write_tag">Write to NFC Tag</string> <string name="message_tap_tag">Tap the NFC Tag to your device !</string> <string name="hint_message">Message</string> </resources> |
نام های بالا در ادامه برنامه استفاده خواهند شد.
در بخش layout دو دکمه و یک Edittext برای ورود داده قرار دهید همانند زیر
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:gravity="center" tools:context="ir.programchi.nfc.MainActivity"> <EditText android:id="@+id/et_message" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="@string/hint_message"/> <Button android:id="@+id/btn_write" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@+id/et_message" android:layout_marginTop="@dimen/activity_horizontal_margin" android:text="@string/message_write_tag" style="@style/Widget.AppCompat.Button.Colored"/> <Button android:id="@+id/btn_read" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@+id/btn_write" android:layout_marginTop="@dimen/activity_horizontal_margin" android:text="@string/message_read_tag" style="@style/Widget.AppCompat.Button.Colored"/> </RelativeLayout> |
در ادامه ما یک فرگمنت داریم که اطلاعات خوانده شده در آن نمایش داده می شود بخش layout آن همانند زیر است نام آن برابر با fragment_read.xml است.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" android:padding="@dimen/activity_horizontal_margin"> <TextView android:id="@+id/title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/message_read_tag" android:textAppearance="?android:attr/textAppearanceLarge" android:layout_gravity="center"/> <ImageView android:id="@+id/logo" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="@dimen/activity_horizontal_margin" android:src="@drawable/ic_nfc" android:tint="@color/colorAccent" android:layout_gravity="center"/> <TextView android:id="@+id/tv_message" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="@dimen/activity_horizontal_margin" android:layout_gravity="center" android:textAppearance="?android:attr/textAppearanceMedium"/> </LinearLayout> |
یک فرگمنت دیگر برای نوشتن به نام fragment_write.xml ایجاد کرده و کدهای زیر را در آن قرار دهید.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" android:padding="@dimen/activity_horizontal_margin"> <TextView android:id="@+id/title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:text="@string/message_write_tag" android:textAppearance="?android:attr/textAppearanceLarge"/> <ImageView android:id="@+id/logo" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_marginTop="@dimen/activity_horizontal_margin" android:src="@drawable/ic_nfc" android:tint="@color/colorAccent"/> <ProgressBar android:id="@+id/progress" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_marginTop="@dimen/activity_horizontal_margin" android:visibility="gone"/> <TextView android:id="@+id/tv_message" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_marginTop="@dimen/activity_horizontal_margin" android:text="@string/message_tap_tag"/> </LinearLayout> |
حالا باید Interface درست کنیم این Interface ها بعدا مورد استفاده قرار می گیرند.
1 2 3 4 | public interface Listener { void onDialogDisplayed(); void onDialogDismissed(); } |
مثل دوتا Event کار خواهند کرد.
کدهای مربوط به فایل NFCReadFragment که برای خواندن تگ Nfc مورد استفاده قرار میگیرد همانند زیر است.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | package ir.programchi; import android.app.DialogFragment; import android.content.Context; import android.nfc.FormatException; import android.nfc.NdefMessage; import android.nfc.tech.Ndef; import android.os.Bundle; import android.support.annotation.Nullable; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import java.io.IOException; public class NFCReadFragment extends DialogFragment { public static final String TAG = NFCReadFragment.class.getSimpleName(); public static NFCReadFragment newInstance() { return new NFCReadFragment(); } private TextView mTvMessage; private Listener mListener; @Nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_read,container,false); initViews(view); return view; } private void initViews(View view) { mTvMessage = (TextView) view.findViewById(R.id.tv_message); } @Override public void onAttach(Context context) { super.onAttach(context); mListener = (MainActivity)context; mListener.onDialogDisplayed(); } @Override public void onDetach() { super.onDetach(); mListener.onDialogDismissed(); } public void onNfcDetected(Ndef ndef){ readFromNFC(ndef); } private void readFromNFC(Ndef ndef) { try { ndef.connect(); NdefMessage ndefMessage = ndef.getNdefMessage(); String message = new String(ndefMessage.getRecords()[0].getPayload()); Log.d(TAG, "readFromNFC: "+message); mTvMessage.setText(message); ndef.close(); } catch (IOException | FormatException e) { e.printStackTrace(); } } } |
یک متود به نام initViews داریم که View های ما رو find می کند. چون داریم از فرگمنت استفاده می کنیم در بخش onAttach (این بخش قبلا در بخش فرگمنت ها توضیح داده شده است) یک Instance از MainActivty در Listener میریزیم اگر یادتان باشد در Interface یک void به نام onDialogDisplayed که آن را صدا می زنیم (دو متود onDialogDisplayed و onDialogDismissed در ManiActivity تعریف شده اند و با صدا زدن آنها عملی انجام می شود ).
یک void دیگر به نام onNfcDetected وجود دارد که تشخیص میدهد Nfc موجود است یا نه (منظور تگ Nfc است) در داخل این void یک void دیگر به نام readFromNFC است که کار خواندن را انجام میدهد.
پس خواندن یک Tag Nfc همانند بالا شد.
یک فرگمنت به نام NFCWriteFragment.java وجود دارد که عمل نوشتن بروی تگ Nfc را انجام میدهد و همانند زیر است.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | package ir.programchi; import android.app.DialogFragment; import android.content.Context; import android.nfc.FormatException; import android.nfc.NdefMessage; import android.nfc.NdefRecord; import android.nfc.tech.Ndef; import android.os.Bundle; import android.support.annotation.Nullable; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ProgressBar; import android.widget.TextView; import java.io.IOException; import java.nio.charset.Charset; public class NFCWriteFragment extends DialogFragment { public static final String TAG = NFCWriteFragment.class.getSimpleName(); public static NFCWriteFragment newInstance() { return new NFCWriteFragment(); } private TextView mTvMessage; private ProgressBar mProgress; private Listener mListener; @Nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_write,container,false); initViews(view); return view; } private void initViews(View view) { mTvMessage = (TextView) view.findViewById(R.id.tv_message); mProgress = (ProgressBar) view.findViewById(R.id.progress); } @Override public void onAttach(Context context) { super.onAttach(context); mListener = (MainActivity)context; mListener.onDialogDisplayed(); } @Override public void onDetach() { super.onDetach(); mListener.onDialogDismissed(); } public void onNfcDetected(Ndef ndef, String messageToWrite){ mProgress.setVisibility(View.VISIBLE); writeToNfc(ndef,messageToWrite); } private void writeToNfc(Ndef ndef, String message){ mTvMessage.setText(getString(R.string.message_write_progress)); if (ndef != null) { try { ndef.connect(); NdefRecord mimeRecord = NdefRecord.createMime("text/plain", message.getBytes(Charset.forName("US-ASCII"))); ndef.writeNdefMessage(new NdefMessage(mimeRecord)); ndef.close(); mTvMessage.setText(getString(R.string.message_write_success)); } catch (IOException | FormatException e) { e.printStackTrace(); mTvMessage.setText(getString(R.string.message_write_error)); } finally { mProgress.setVisibility(View.GONE); } } } } |
همانند قبل برخی بخش ها تکراری است فقط به بخش writeToNfc خواهیم پرداخت در اینجا این متود یک متن تست را به تگ nfc نسبت میدهد و در آن ذخیره می کند چون نمیشه خود فایل text رو یعنی String رو ذخیره کرد مقدار Ascii آن را دریافت و در Nfc تگ قرار خواهیم داد.
به همین راحتی
بخش اصلی برنامه یا MainActivity
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 | package ir.programchi; import android.app.PendingIntent; import android.content.Intent; import android.content.IntentFilter; import android.nfc.NfcAdapter; import android.nfc.Tag; import android.nfc.tech.Ndef; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.widget.Button; import android.widget.EditText; import android.widget.Toast; public class MainActivity extends AppCompatActivity implements Listener{ public static final String TAG = MainActivity.class.getSimpleName(); private EditText mEtMessage; private Button mBtWrite; private Button mBtRead; private NFCWriteFragment mNfcWriteFragment; private NFCReadFragment mNfcReadFragment; private boolean isDialogDisplayed = false; private boolean isWrite = false; private NfcAdapter mNfcAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initViews(); initNFC(); } private void initViews() { mEtMessage = (EditText) findViewById(R.id.et_message); mBtWrite = (Button) findViewById(R.id.btn_write); mBtRead = (Button) findViewById(R.id.btn_read); mBtWrite.setOnClickListener(view -> showWriteFragment()); mBtRead.setOnClickListener(view -> showReadFragment()); } private void initNFC(){ mNfcAdapter = NfcAdapter.getDefaultAdapter(this); } private void showWriteFragment() { isWrite = true; mNfcWriteFragment = (NFCWriteFragment) getFragmentManager().findFragmentByTag(NFCWriteFragment.TAG); if (mNfcWriteFragment == null) { mNfcWriteFragment = NFCWriteFragment.newInstance(); } mNfcWriteFragment.show(getFragmentManager(),NFCWriteFragment.TAG); } private void showReadFragment() { mNfcReadFragment = (NFCReadFragment) getFragmentManager().findFragmentByTag(NFCReadFragment.TAG); if (mNfcReadFragment == null) { mNfcReadFragment = NFCReadFragment.newInstance(); } mNfcReadFragment.show(getFragmentManager(),NFCReadFragment.TAG); } @Override public void onDialogDisplayed() { isDialogDisplayed = true; } @Override public void onDialogDismissed() { isDialogDisplayed = false; isWrite = false; } @Override protected void onResume() { super.onResume(); IntentFilter tagDetected = new IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED); IntentFilter ndefDetected = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED); IntentFilter techDetected = new IntentFilter(NfcAdapter.ACTION_TECH_DISCOVERED); IntentFilter[] nfcIntentFilter = new IntentFilter[]{techDetected,tagDetected,ndefDetected}; PendingIntent pendingIntent = PendingIntent.getActivity( this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0); if(mNfcAdapter!= null) mNfcAdapter.enableForegroundDispatch(this, pendingIntent, nfcIntentFilter, null); } @Override protected void onPause() { super.onPause(); if(mNfcAdapter!= null) mNfcAdapter.disableForegroundDispatch(this); } @Override protected void onNewIntent(Intent intent) { Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); Log.d(TAG, "onNewIntent: "+intent.getAction()); if(tag != null) { Toast.makeText(this, getString(R.string.message_tag_detected), Toast.LENGTH_SHORT).show(); Ndef ndef = Ndef.get(tag); if (isDialogDisplayed) { if (isWrite) { String messageToWrite = mEtMessage.getText().toString(); mNfcWriteFragment = (NFCWriteFragment) getFragmentManager().findFragmentByTag(NFCWriteFragment.TAG); mNfcWriteFragment.onNfcDetected(ndef,messageToWrite); } else { mNfcReadFragment = (NFCReadFragment)getFragmentManager().findFragmentByTag(NFCReadFragment.TAG); mNfcReadFragment.onNfcDetected(ndef); } } } } } |
دو تا Void به نام های showReadFragment و showWriteFragment به برای نمایش فرگمنت ها مورد استفاده قرار میگیرد. در بخش onResume شاید بشه گفت یه جورایی یک Listent تعریف شده تا در صورتی که کارتی که حاوی تگ بود به گوشی نزدیک شد یکسری عملیات انجام شود interfcae ها که تعریف شده بود نیز مشخص است onDialogDisplayed و onDialogDismissed که متوجه می شوید چه عملی در حال شبیه سازی کردن است. بخش onNewIntent به منظور گرفتن داده از فرگمنت است و بررسی می شود که آیا باید تگ نوشته شود یا Detect شود.
این آموزش هم به پایان رسید.
موفق و پیروز باشید.
سلام
متاسفانه بعد از اینکه read میکنم این ارور رو میده:
Attempt to invoke virtual method ‘void android.nfc.tech.Ndef.connect()’ on a null object reference
یعنی تشخصی میده و میگه NFC Tag detected ولی موقع اجرای متود readFromNFC() این ارورو میده!
سلام و درود با چی دارید تست می کنید ؟ با تگ یا کارت مترو !
بانام خدا
سلام
از کارت مترو و اتوبوس و دانشجویی چطور میشه کپی کرد و اجرا کرد؟ نرم افزار خوبی میشناسید؟
اکثر نرم افزارها میگن نوع برچسب nfc پشتیبانی نشد.
چیزی نیست کاری به نوع نداشته باشه و فقط کپی کنه و اجرا؟
سلام خیر امکان نفوظ به این نوع کارت ها وجود ندارد زیرا باید تگ مربوط به هر کارت را که می خواهید را داشته باشید یا اینکه result آن را دریافت کنید و ببینید با چه چیزی نوشته شده است با گوشی می توان این کار را کرد و دستگاه های خارجی نیز برای اینکار وجود دارد.
موفق باشید.
ممنون بابت محتوای مفیدتون
اگه یه ریدر rfid داشته باشیم و بخوایم یه برنامه ساده برای خوندن چندتا تگ براش بنویسیم به طوری که بعد از خوندن یکی از تگهای خونده شده رو انتخاب کنیم که اطلاعاتش رو بهمون نشون بده چیکار باید بکنیم باز همین مثال رو میشه اونجا هم استفاده کرد ؟
ممنون میشم راهنمایی کنید
سلام وقتتون بخیر آیا برای خواندن کارت های RFID هم استفاده میشه کرد؟