【问题标题】:Write NFC data on an tag with Android Studio使用 Android Studio 在标签上写入 NFC 数据
【发布时间】:2019-12-19 07:49:08
【问题描述】:

我正在创建一个应用程序,在该应用程序中,我必须将来自文件的一系列值写入 NFC 卡,我一直在阅读,但我不知道从哪里真正开始,我有一个几个疑问。

首先,我知道理想的做法是创建一个处理 NFC 的类,尽管我认为这是可选的并且可以在同一个类中完成。问题是我看到的教程只使用了activity,并且使用了onNewIntent方法。

在一个片段中我不能调用这个方法,所以这是我失败的第一步,我不知道这个方法是否必要,因为据我了解这是启动应用程序,即使它被关闭如果是读者,如果我错了,请纠正我。如果您能指导我应该做什么,我将不胜感激,因为在阅读了这么多之后,我有点发疯了。

【问题讨论】:

    标签: android kotlin nfc


    【解决方案1】:

    我首先要考虑如何存储数据。

    数据是为您的应用定制的,还是您想与其他应用共享?

    应用程序会只写入一次数据还是会更新它(想要将数据附加到存储在卡上的现有数据中?

    更新:来自您的 cmets 关于数据类型的信息,您可能最好使用更高级别的 NDEF 格式来使用自定义 mime 类型存储您的数据。这是假设您选择的卡类型支持这一点。 请注意,我给出的示例是使用低级命令读取/写入逐页读取和写入。

    你要存储多少字节的数据(影响卡片技术)

    您可能还想考虑要使用哪种 NFC 卡技术,可能是 NTAG 21x 系列卡之一的不错选择。

    您要定位的最低 Android 版本是多少?

    我不会使用 newIntent 方法,因为这对于写入数据非常不可靠,如果您的目标是足够高的 Android 版本,我会使用 enableReaderMode

    https://developer.android.com/reference/android/nfc/NfcAdapter.html#enableReaderMode(android.app.Activity,%20android.nfc.NfcAdapter.ReaderCallback,%20int,%20android.os.Bundle)

    您需要考虑的一些答案会影响示例的一些细节。

    更新:基于 cmets 即使您使用的是 Fragments,我仍然会将 NFC 处理机制放在 Activity 中。

    这是因为操作系统仍在处理标签发现,如果您不在每个 Fragment 中“声明”NFC 硬件,那么特别是对于 NDEF 数据格式,操作系统可能会显示一个屏幕如果用户在错误的时间出示卡片,则会给您的应用程序带来糟糕的用户体验。

    在我的多 Activity 应用程序中,我在每个 Activity 中“声明”了 NFC 硬件,即使其中很多都执行“发现标签时,什么也不做”,因为它们不是 NFC Activity。

    因此,除非您想在每个 Fragment 中编写相同的代码,否则最好从您的一个 Activity 中调用 NFC 内容,然后在 onTagDiscovered 中执行类似(伪代码)的操作:-

    更新:

    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.
    

    或者你可以在应用打开的任何时候写卡片(最好还是在活动中而不是在任何片段中完成)

    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.
    

    抱歉,我无法在 Kotlin 中做示例,但这里是 Java 示例的准系统,从我的应用程序中提取(未经测试,因此可能存在复制和粘贴错误)

    
    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;
            }
        }
    
    }
    
    

    【讨论】:

    • 它们是要记录日期和时间等基本数据的卡片,其余的都是整体和字符串。在记录这些相同的卡片后,它们将再次被用于记录相同的字段但不同的值。你给我的例子是一个activity,但是我用的是Fragment,有什么变化?
    • 在 Fragment 中稍微复杂一些,这有点取决于 Fragment 的使用方式(如图所示),但是 Fragment 可以具有与 Activity 相同的生命周期方法以及 Callback 和实际读取代码并在任何地方(我在一个单独的班级中有我的)
    • 嗯嗯好的,明天我试试看能不能弄到。
    • 如果您告诉我们您是如何使用片段的(它是您活动中的唯一片段还是显示为 viewpager 视图的一部分),那么它可能会帮助我调整示例以匹配您的需求
    • 在我的应用程序中,我只有一个扩展 BaseFragment 的 BaseActivity,并且所有片段都从该 BaseFragment 扩展。导航是通过导航组件完成的,但一切都是片段,整个应用程序中只有一个活动。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多