Write NFC data on an tag with Android Studio

前端 未结 1 1346
走了就别回头了
走了就别回头了 2021-01-26 11:38

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

相关标签:
1条回答
  • 2021-01-26 12:24

    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;
            }
        }
    
    }
    
    
    0 讨论(0)
提交回复
热议问题