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();
}
我正在尝试读取 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();
}