I\'m creating an application in which I have to write a series of values that come to me from a file to an NFC card and I\'ve been reading and I don\'t know where to really star
The first place I would start is thinking about how to store the data.
Is the data custom to your application or do you want to share it with other App's?
Will the App be just writing the data once or will it be updating it (wanting to Append Data to existing data stored on the card?
Update: from your comments about the data type you are probably better using the higher level NDEF format to store your Data using a custom mime type. This is assuming your chosen card type supports this. Note the example I gave is reading/writing using low level commands read and writing page by page.
How many bytes of data do you want to store (Influences the card technology)
You probably want to also think about what NFC card technology you want to use, probably a good choice of one of the NTAG 21x series of cards.
What is the minimum version of Android you want to target?
I would not use the newIntent method as this is very unreliable for writing data, I would use the enableReaderMode
if you are targeting a high enough version of Android.
https://developer.android.com/reference/android/nfc/NfcAdapter.html#enableReaderMode(android.app.Activity,%20android.nfc.NfcAdapter.ReaderCallback,%20int,%20android.os.Bundle)
Some of the answers to what you need to think about will affect some of the details of the example.
Update: based on comments Even though you are using Fragments I would still put the mechanics of NFC handling in the Activity.
The reason for this is because the OS is still handling tag discovery, if you don't "claim" the NFC hardware in every Fragment then it is possible especially with the NDEF data format, for the OS to display a screen over your App if the user present a card at the wrong time, giving a bad user experience.
In my multi Activity App I "claim" the NFC hardware in every Activity even if a lot of them do "On Tag discovered, do nothing" because they are not the NFC Activity.
So unless you want to write the same code in every Fragment, it would be much better to call the NFC stuff from your one Activity and then in onTagDiscovered
does something like (pseudo code):-
Updated:
if displaying the NFC user prompt Fragment.
get data to file.
write data to the card.
Notify user that it is done.
else
do nothing when other fragments are displayed.
or you could have card writing at any time the App is open (again best done in activity not in any fragment)
If card is presented no matter what fragment is being display
get data from the file
write data to the card
Notify user that it is done.
Sorry I cannot do an example in Kotlin but here is a barebone of a Java Example, extracted from my App (not tested, so there could be copy and pasted errors)
public class MainActivity extends AppCompatActivity implements NfcAdapter.ReaderCallback{
private NfcAdapter mNfcAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
// All normal onCreate Stuff
// Listen to NFC setting changes
this.registerReceiver(mReceiver, filter);
}
// Listen for NFC being turned on while in the App
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (action.equals(NfcAdapter.ACTION_ADAPTER_STATE_CHANGED)) {
final int state = intent.getIntExtra(NfcAdapter.EXTRA_ADAPTER_STATE,
NfcAdapter.STATE_OFF);
switch (state) {
case NfcAdapter.STATE_OFF:
// Tell the user to turn NFC on if App requires it
break;
case NfcAdapter.STATE_TURNING_OFF:
break;
case NfcAdapter.STATE_ON:
enableNfc();
break;
case NfcAdapter.STATE_TURNING_ON:
break;
}
}
}
};
@Override
protected void onResume() {
super.onResume();
enableNfc();
}
@Override
protected void onPause() {
super.onPause();
if(mNfcAdapter!= null)
mNfcAdapter.disableReaderMode(this);
}
private void enableNfc(){
mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
if(mNfcAdapter!= null && mNfcAdapter.isEnabled()) {
// Work around some buggy hardware that checks for cards too fast
Bundle options = new Bundle();
options.putInt(NfcAdapter.EXTRA_READER_PRESENCE_CHECK_DELAY, 1000);
// Listen for all types of card when this App is in the foreground
// Turn platform sounds off as they misdirect users when writing to the card
// Turn of the platform decoding any NDEF data
mNfcAdapter.enableReaderMode(this,
this,
NfcAdapter.FLAG_READER_NFC_A |
NfcAdapter.FLAG_READER_NFC_B |
NfcAdapter.FLAG_READER_NFC_F |
NfcAdapter.FLAG_READER_NFC_V |
NfcAdapter.FLAG_READER_NFC_BARCODE |
NfcAdapter.FLAG_READER_SKIP_NDEF_CHECK |
NfcAdapter.FLAG_READER_NO_PLATFORM_SOUNDS,
options);
} else {
// Tell the user to turn NFC on if App requires it
}
}
public void onTagDiscovered(Tag tag) {
// This is run in a separate Thread to UI
StringBuilder Uid = new StringBuilder();
boolean successUid = getUID(tag, Uid);
if (!successUid){
// Not a successful read
return;
} else {
// Feedback to user about successful read
Vibrator v = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
v.vibrate(500);
runOnUiThread(new Runnable() {
@Override
public void run() {
// Update the UI / notify user
}
});
// Finish Task
try {
Uri notification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
Ringtone r = RingtoneManager.getRingtone(getApplicationContext(), notification);
r.play();
} catch (Exception e) {
e.printStackTrace();
}
}
}
public boolean getUID(Tag tag, StringBuilder Uid){
NfcA mNfcA = NfcA.get(tag);
if (mNfcA != null) {
// The tag is NfcA capable
try {
mNfcA.connect();
// Do a Read operation at page 0 an 1
byte[] result = mNfcA.transceive(new byte[] {
(byte)0x3A, // FAST_READ
(byte)(0 & 0x0ff),
(byte)(1 & 0x0ff),
});
if (result == null) {
// either communication to the tag was lost or a NACK was received
// Log and return
return false;
} else if ((result.length == 1) && ((result[0] & 0x00A) != 0x00A)) {
// NACK response according to Digital Protocol/T2TOP
// Log and return
return false;
} else {
// success: response contains ACK or actual data
for (int i = 0; i < result.length; i++) {
// byte 4 is a check byte
if (i == 3) continue;
Uid.append(String.format("%02X ", result[i]));
}
// Close and return
try {
mNfcA.close();
} catch (IOException e) {
}
return true;
}
} catch (TagLostException e) {
// Log and return
return false;
} catch (IOException e){
// Log and return
return false;
} finally {
try {
mNfcA.close();
} catch (IOException e) {
}
}
} else {
// Log error
return false;
}
}
}