Android 读取 Mifare 经典卡

Android reading Mifare classic card

我正在尝试读取 mifare 卡。我可以读取 Tag 对象,但无法读取 NdefMessages ... 当我调用检索 ndefMessages 的意图时,它 returns 一个空值而不是一个数组。但是我可以读取 ID 和技术列表,当我用另一个应用程序读取它时,我可以看到内容,所以卡上有数据。

using Android.App;
using Android.Content;
using Android.Content.PM;
using Android.Nfc;
using Android.Nfc.Tech;
using Android.OS;
using Android.Runtime;
using System;
using System.Linq;
using System.Text;

namespace NfcDemo.Droid
{
    [Activity(Label = "NfcDemo", Icon = "@mipmap/icon", Theme = "@style/MainTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation, LaunchMode = LaunchMode.SingleTop | LaunchMode.SingleTask)]
    public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
    {
        private NfcAdapter _nfcAdapter;

        protected override void OnCreate(Bundle savedInstanceState)
        {
            TabLayoutResource = Resource.Layout.Tabbar;
            ToolbarResource = Resource.Layout.Toolbar;

            base.OnCreate(savedInstanceState);

            Xamarin.Essentials.Platform.Init(this, savedInstanceState);
            global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
            LoadApplication(new App());

            _nfcAdapter = NfcAdapter.GetDefaultAdapter(this);
        }
        public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Android.Content.PM.Permission[] grantResults)
        {
            Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);

            base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
        }

        protected override void OnResume()
        {
            base.OnResume();
            if (_nfcAdapter == null)
            {
                var alert = new AlertDialog.Builder(this).Create();
                alert.SetMessage("NFC is not supported on this device.");
                alert.SetTitle("NFC Unavailable");
                alert.Show();
            }
            else
            {
                var ndefDiscover = new IntentFilter(NfcAdapter.ActionNdefDiscovered);
                var techDiscover = new IntentFilter(NfcAdapter.ActionTechDiscovered);
                var tagDetected = new IntentFilter(NfcAdapter.ActionTagDiscovered);

                var filters = new[] { tagDetected, techDiscover, ndefDiscover };

                var intent = new Intent(this, this.GetType()).AddFlags(ActivityFlags.SingleTop);
                var pendingIntent = PendingIntent.GetActivity(this, 0, intent, 0);
                _nfcAdapter.EnableForegroundDispatch(this, pendingIntent, filters, null);
            }
        }

        protected override void OnPause()
        {
            base.OnPause();
            _nfcAdapter.DisableForegroundDispatch(this);
        }

        public static string ByteArrayToString(byte[] ba)
        {
            return BitConverter.ToString(ba).Replace("-", "");
        }

        protected override void OnNewIntent(Intent intent)
        {
            base.OnNewIntent(intent);
            if (intent.Action == NfcAdapter.ActionTagDiscovered)
            {
                var tag = intent.GetParcelableExtra(NfcAdapter.ExtraTag) as Tag;
                if (tag != null)
                {
                    var techs = tag.GetTechList();
                    var id = tag.GetId();
                    var hexstring = ByteArrayToString(tag.GetId());

                    var rawMessages = intent.GetParcelableArrayExtra(NfcAdapter.ExtraNdefMessages);

                    if (rawMessages != null)
                    {
                        foreach (var message in rawMessages.Cast<NdefMessage>())
                        {
                            foreach (var record in message.GetRecords())
                            {
                                var typeBytes = record.GetTypeInfo();
                                var payloadBytes = record.GetPayload();
                                var type = Encoding.UTF8.GetString(typeBytes);
                                var payload = Encoding.UTF8.GetString(payloadBytes);
                            }
                        }
                    }
                }
            }
        }
    }
}

你应该在 onNewIntent

中寻找 NfcAdapter.ACTION_NDEF_DISCOVERED 而不是 NfcAdapter.ActionTagDiscovered

但是由于您没有在 intent 过滤器中正确要求发送 NDEF 消息,因此您不会收到任何消息,您应该添加 ndefDiscover.addDataType("*/*"); 以在通过之前告诉它您想要什么类型的 NDEF 消息EnableForegroundDispatch

的过滤器

注意“*/*”是发送所有类型,没有定义数据类型是发送零数据类型。

因为 TagDiscovered 是比 NDEF 更低的类型,即使您的卡片上有 NDEF 消息,后台服务也不会解析它们以将它们放入 Extras 字段,因为它不希望您使用它们。

这方面的文档位于 https://developer.android.com/guide/topics/connectivity/nfc/advanced-nfc#foreground-dispatch

Mifare Classic 不能与 NDEF 一起使用,请尝试这样的操作:

using Android.Nfc;
using Android.Nfc.Tech;

protected override void OnNewIntent(Intent intent)
{
    base.OnNewIntent(intent);

    Tag tag = intent.GetParcelableExtra(NfcAdapter.ExtraTag) as Tag;

    if (tag == null) return;
    
    MifareClassic card = MifareClassic.Get(tag);
    card.Connect();
    //read block 1 of sector 0
    if (card.AuthenticateSectorWithKeyA(0, new byte[] {0xff,0xff,0xff,0xff,0xff,0xff})) //replace if you have other auth keys
    {
        byte[] data = card.ReadBlock(1);
    }
    card.Close(); 
}