Android读写nfc

问题描述 投票:1回答:1

我正在编写一个可读取和写入标签的Android应用程序。当我读取所有内容时,一切正常,当我尝试将数据保存在nfc标记上时,标记第一个读取的数据并再次打开活动,如何阻止意图读取并正确保存数据?

清单

<activity
                android:name=".DeviceDetails.DeviceDetailsMain_NFC">
                <intent-filter>
                    <action android:name="android.nfc.action.NDEF_DISCOVERED" />
                    <category android:name="android.intent.category.DEFAULT" />
                    <data android:mimeType="text/plain" />
                </intent-filter>
                <meta-data
                    android:name="android.nfc.action.TECH_DISCOVERED"
                    android:resource="@xml/nfc_tech_filter" />
</activity>

这是我的活动代码:

@Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.device_details_activity_main);

            mDatabaseHelper = new DatabaseHelper(DeviceDetailsMain_NFC.this);
            preferences = getSharedPreferences("DevDetails", MODE_PRIVATE);

            context = this;

            nfcAdapter = NfcAdapter.getDefaultAdapter(this);

            readFromIntent(getIntent());
            pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
            IntentFilter tagDetected = new IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED);
            tagDetected.addCategory(Intent.CATEGORY_DEFAULT);
            writeTagFilters = new IntentFilter[] { tagDetected };

        }

        private void setupViewPager(ViewPager viewPager, String DEV_ID) {
            SectionsPageAdapter adapter = new SectionsPageAdapter(getSupportFragmentManager());
            adapter.addFragment(new Tab1Fragment(), getResources().getString(R.string.frag_ddm_device));
            if(mDatabaseHelper.checkParameters(DEV_ID))adapter.addFragment(new Tab4Fragment(), getResources().getString(R.string.frag_ddm_parameters));
            if(mDatabaseHelper.isDevice(DEV_ID)) adapter.addFragment(new Tab3Fragment(), getResources().getString(R.string.frag_ddm_events));
            if(mDatabaseHelper.getModelID(DEV_ID) != null) adapter.addFragment(new Tab2Fragment(), getResources().getString(R.string.frag_ddm_model));
            viewPager.setAdapter(adapter);
        }

        public boolean writeNFC(String ID){
            if(myTag != null) {
                try {
                    write(ID, myTag);
                    return true;
                } catch (IOException e) {
                    return false;
                } catch (FormatException e) {
                    return false;
                }
            }else{
                return false;
            }
        }

        /**********************************Read From NFC Tag***************************/
        private void readFromIntent(Intent intent) {
            String action = intent.getAction();
            if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(action)
                    || NfcAdapter.ACTION_TECH_DISCOVERED.equals(action)
                    || NfcAdapter.ACTION_NDEF_DISCOVERED.equals(action)) {
                Parcelable[] rawMsgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
                NdefMessage[] msgs = null;
                if (rawMsgs != null) {
                    msgs = new NdefMessage[rawMsgs.length];
                    for (int i = 0; i < rawMsgs.length; i++) {
                        msgs[i] = (NdefMessage) rawMsgs[i];
                    }
                }
                if (msgs == null || msgs.length == 0) return;

                String text = "";
                byte[] payload = msgs[0].getRecords()[0].getPayload();
                String textEncoding = ((payload[0] & 128) == 0) ? "UTF-8" : "UTF-16"; // Get the Text Encoding
                int languageCodeLength = payload[0] & 0063; // Get the Language Code, e.g. "en"
                // String languageCode = new String(payload, 1, languageCodeLength, "US-ASCII");

                try {
                    // Get the Text
                    text = new String(payload, languageCodeLength + 1, payload.length - languageCodeLength - 1, textEncoding);
                } catch (UnsupportedEncodingException e) {
                    Log.e("UnsupportedEncoding", e.toString());
                }
                    saveData(text);
                    mViewPager = findViewById(R.id.view_pager);
                    setupViewPager(mViewPager, text);
                    TabLayout tabLayout = findViewById(R.id.tabs);
                    tabLayout.setupWithViewPager(mViewPager);

                    String devName = mDatabaseHelper.getDevName(text);
                    if (devName != null) {
                        getSupportActionBar().setTitle(devName);
                    } else {
                        getSupportActionBar().setTitle("");
                    }
            }else{
                    DEV_ID = preferences.getString("devID", "");
                    mViewPager = findViewById(R.id.view_pager);
                    setupViewPager(mViewPager, DEV_ID);
                    TabLayout tabLayout = findViewById(R.id.tabs);
                    tabLayout.setupWithViewPager(mViewPager);

                    String devName = mDatabaseHelper.getDevName(DEV_ID);
                    if (devName != null) {
                        getSupportActionBar().setTitle(devName);
                    } else {
                        getSupportActionBar().setTitle("");
                    }
            }
        }
        private void saveData(String dane) {
            SharedPreferences.Editor preferencesEditor = preferences.edit();
            preferencesEditor.putString("devID", dane);
            preferencesEditor.commit();
        }
        /**********************************Write to NFC Tag****************************/
        private void write(String text, Tag tag) throws IOException, FormatException {
            NdefRecord[] records = { createRecord(text) };
            NdefMessage message = new NdefMessage(records);
            // Get an instance of Ndef for the tag.
            Ndef ndef = Ndef.get(tag);
            // Enable I/O
            ndef.connect();
            // Write the message
            ndef.writeNdefMessage(message);
            // Close the connection
            ndef.close();
        }
        private NdefRecord createRecord(String text) throws UnsupportedEncodingException {
            String lang       = "en";
            byte[] textBytes  = text.getBytes();
            byte[] langBytes  = lang.getBytes(StandardCharsets.US_ASCII);
            int    langLength = langBytes.length;
            int    textLength = textBytes.length;
            byte[] payload    = new byte[1 + langLength + textLength];

            // set status byte (see NDEF spec for actual bits)
            payload[0] = (byte) langLength;

            // copy langbytes and textbytes into payload
            System.arraycopy(langBytes, 0, payload, 1,              langLength);
            System.arraycopy(textBytes, 0, payload, 1 + langLength, textLength);

            NdefRecord recordNFC = new NdefRecord(NdefRecord.TNF_WELL_KNOWN,  NdefRecord.RTD_TEXT,  new byte[0], payload);

            return recordNFC;
        }
        @Override
        protected void onNewIntent(Intent intent) {
            super.onNewIntent(intent);
                setIntent(intent);
                readFromIntent(intent);
                if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(intent.getAction())) {
                    myTag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
                }
        }
        @Override
        public void onPause(){
            super.onPause();
            WriteModeOff();
        }
        @Override
        public void onResume(){
            super.onResume();
            WriteModeOn();
        }
        /**********************************Enable Write********************************/
        private void WriteModeOn(){
            writeMode = true;
            nfcAdapter.enableForegroundDispatch(this, pendingIntent, writeTagFilters, null);
        }
        /**********************************Disable Write*******************************/
        private void WriteModeOff(){
            writeMode = false;
            nfcAdapter.disableForegroundDispatch(this);
        }
    }

片段代码:

btnWrite.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {

                            final Handler handler = new Handler();
                            final int delay = 100; //milliseconds

                            final AlertDialog alertDialog = new AlertDialog.Builder(context).create();
                            alertDialog.setTitle(R.string.save_to_NFC_tag);
                            alertDialog.setMessage(getContext().getResources().getString(R.string.approach_an_NFC_Tag));
                            alertDialog.setButton(AlertDialog.BUTTON_POSITIVE, getContext().getResources().getString(R.string.ok),
                                    new DialogInterface.OnClickListener() {
                                        public void onClick(DialogInterface dialog, int which) {
                                            handler.removeCallbacks(runnable);
                                            dialog.dismiss();
                                        }
                                    });
                            alertDialog.show();

                            handler.postDelayed(runnable = new Runnable(){
                                public void run(){
                                        if (deviceDetailsMain_nfc.writeNFC(DEV_ID)) {
                                            alertDialog.setMessage(getContext().getResources().getString(R.string.record_completed));
                                            handler.removeCallbacks(runnable);
                                        }
                                    handler.postDelayed(this, delay);
                                }
                            }, delay);

                        }
                    });

我有一个运行4个片段的活动,在活动中读取代码,并且从片段中调用写作机制

java android nfc
1个回答
0
投票

对于写入,我不会使用enableForegroundDispatch方法,它会误导用户将卡移出范围太快,从而导致在实际用户使用时出现许多写入错误和数据损坏。

这是因为声音提示会在操作系统读取卡后立即发生,而您的代码才有机会对其进行写入。

我会在要控制声音提示的地方使用enableReaderMode

更新请注意,使用enabledReaderMode时,您仍然可以在清单中放置Intent过滤器,以要求Android OS在看到特定类型的标签时启动您的应用,而清单Intent过滤器生成的Intent始终在Activity的onCreate方法中进行处理无论您在“活动”中如何处理卡片。

[enableForegroundDispatch同样也不可靠读取,因为操作系统在看起来像没有窗口的活动中处理NFC读取,因此您的活动在读取时会暂停”

我已经通过enableForegroundDispatch进行了真实的用户测试,当您的应用位于前台时,该标签进入范围,您的应用被暂停,该标签超出范围,然后回到范围之前,您的应用已经机会被恢复,因此OS认为没有东西在等待它的Intent,因此打开它自己的窗口,显示NDEF数据的基本屏幕,而不是尝试将Intent传递给仍暂停的Activity。

另一个建议是,如果您可以轻松地使用NDEF格式,因为操作系统知道NDEF会尝试使用它来做事,使用您自己的格式意味着操作系统不太可能干扰您的操作。但是,如果您要写的数据多于一页数据,则会更加复杂,但是您确实可以获得更好的错误处理能力。

使用enableReaderMode,读卡时您的应用不会暂停(相反,卡交互是在应用中的单独线程中处理的),您可以控制声音,因此可以在完成声音后播放声音而不是任务完成时写。

答案enableReaderMode写页面中的低级读取https://stackoverflow.com/a/59397667/2373819的示例与读取在结构上没有太大差异。

更新:重新读取您的代码,似乎在编写时就假定该标签在范围内。因为标签可以轻松,频繁地进入或离开范围,所以一旦触发onNewIntent,就可以更加可靠地进行写入。

您应该将onNewIntent视为一个通知,告知您标签在您可以读写标签的范围内(在enableReaderMode方法中,它被称为onTagDiscovered,因为它的确是这样。)

更新:添加了有关如何处理读写逻辑以实现可靠写入的流程图。Read/Write Logic

© www.soinside.com 2019 - 2024. All rights reserved.