Plugin.NFC
Plugin.NFC copied to clipboard
working on formatting
Have an issue when writing to tags that are not initialized but are NDefFormattable. For xamarin.forms i used to use my own modified version of https://github.com/poz1/NFCForms This added both mifarelight format support and regular ndefformat support. Currently attempting to replace the Publish command in a fork with his write function. So far it seems to work. Just have to re-implement clear / readonly
https://github.com/Gekidoku/Plugin.NFC to track progress
Note i will only do this for android. as iOS NFC is a nightmare
internal void WriteMessageAndFormat(ITagInfo tagInfo, bool makeReadOnly = false)
{
if (_currentTag == null)
{
throw new Exception(Configuration.Messages.NFCErrorMissingTag);
}
Ndef ndef = Ndef.Get(_currentTag);
//Check if the tag can be NDEFformatted
var formatcheck = _currentTag.GetTechList().Contains("android.nfc.tech.NdefFormatable");
//Previous check didnt compare both just ndef being null can also mean its not formatted
if (ndef == null && formatcheck == false)
{
throw new Exception(Configuration.Messages.NFCErrorNotCompliantTag);
}
//Not formatted but can be formatted
if (ndef == null && formatcheck == true)
{
NdefFormatable formatable = NdefFormatable.Get(_currentTag);
//For some reason this could still give null even if formatcheck gave a true so /shrug
if (formatable == null)
{
throw new Exception(Configuration.Messages.NFCErrorNotCompliantTag);
}
try
{
formatable.Connect();
OnTagConnected?.Invoke(null, EventArgs.Empty);
}
catch
{
throw new Exception(Configuration.Messages.NFCErrorMissingTag);
}
//old size check.
//int size = message.ToByteArray().Length;
try
{
List<Android.Nfc.NdefRecord> records = new List<Android.Nfc.NdefRecord>();
for (int i = 0; i < tagInfo.Records.Length; i++)
{
var record = tagInfo.Records[i];
if (GetAndroidNdefRecord(record) is NdefRecord ndefRecord)
records.Add(ndefRecord);
};
Android.Nfc.NdefMessage msg = new Android.Nfc.NdefMessage(records.ToArray());
//This Format works with Mifare Classic and NTAG213. Fails with ultralight. these are the chips I tested it with.
//Both with pre used ones and with factory new ones.
if(makeReadOnly)
formatable.FormatReadOnly(msg);
else
formatable.Format(msg);
}
catch (TagLostException tle)
{
throw new Exception(Configuration.Messages.NFCErrorMissingTag + " " + tle.Message);
}
catch (Android.Nfc.FormatException fe)
{
throw new Exception(Configuration.Messages.NFCErrorMissingTag + " " + fe.Message);
}
catch (Exception e)
{
//Assume that if we are here the tag is still touching the device, our message is correct, and the tag isnt busted.
try
{
//we close this tech so we can open it as ultralight
formatable.Close();
//check if the connected chip is ultralight.
if (_currentTag.GetTechList().Contains("android.nfc.tech.MifareUltralight"))
{
MifareUltralight ultralight = MifareUltralight.Get(_currentTag);
if (ultralight != null)
{
try
{
//connect with ultralight tech
ultralight.Connect();
//Found this on a stackoverflow question that had the same problem, apparently this sets it up to be NFC Forum Type 2 tag.
//https://stackoverflow.com/questions/35985287/formatting-a-mifare-ultralight-to-ndef-throw-io-exception
ultralight.Transceive(new byte[]
{
(byte)0xA2,//Write
(byte)0x03,//Page Nr = 3
(byte)0xE1,(byte)0x10,(byte)0x06, (byte)0x00//capability container (mapping version 1.0, 48 bytes for data available, read/ write allowed)
});
ultralight.Transceive(new byte[]
{
(byte)0xA2,//Write
(byte)0x04,//Page nr = 4
(byte)0x03, (byte)0x00,(byte)0xFE,(byte)0x00 // empty NDEF TLV, Terminator TLV
});
}
catch (Exception e1)
{
}
finally
{
//Now the tag is formatted to accept NDEF
try
{
//Close this tech connection as this one doesnt have WriteNdef
ultralight.Close();
//Get the tag as Ndef
ndef = Ndef.Get(_currentTag);
//Connect
ndef.Connect();
//Check the message again JIC
List<Android.Nfc.NdefRecord> recordsFormat = new List<Android.Nfc.NdefRecord>();
for (int i = 0; i < tagInfo.Records.Length; i++)
{
var record = tagInfo.Records[i];
if (GetAndroidNdefRecord(record) is NdefRecord ndefRecord)
recordsFormat.Add(ndefRecord);
};
Android.Nfc.NdefMessage msg = new Android.Nfc.NdefMessage(recordsFormat.ToArray());
//Write and close
ndef.WriteNdefMessage(msg);
if (makeReadOnly)
ndef.MakeReadOnly();
ndef.Close();
}
catch
{
}
}
}
}
}
catch (Exception eform)
{
throw new Exception(Configuration.Messages.NFCErrorWrite + " " + eform.ToString());
}
}
finally
{
//Used to not have the ultralight code in so i had to close here
//formatable.Close();
OnTagDisconnected?.Invoke(null, EventArgs.Empty);
}
}
else
{
//Rest as normal
try
{
ndef.Connect();
OnTagConnected?.Invoke(null, EventArgs.Empty);
}
catch
{
throw new Exception("Tag Error: No Tag nearby");
}
if (!ndef.IsWritable)
{
ndef.Close();
throw new Exception(Configuration.Messages.NFCWritingNotSupported + " Locked");
}
try
{
List<Android.Nfc.NdefRecord> records = new List<Android.Nfc.NdefRecord>();
for (int i = 0; i < tagInfo.Records.Length; i++)
{
var record = tagInfo.Records[i];
if (GetAndroidNdefRecord(record) is NdefRecord ndefRecord)
records.Add(ndefRecord);
}
Android.Nfc.NdefMessage msg = new Android.Nfc.NdefMessage(records.ToArray());
ndef.WriteNdefMessage(msg);
if (makeReadOnly)
ndef.MakeReadOnly();
}
catch (TagLostException tle)
{
throw new Exception("Tag Lost Error: " + tle.Message);
}
catch (Android.Nfc.FormatException fe)
{
throw new Exception("Tag Format Error: " + fe.Message);
}
catch (Exception e)
{
throw new Exception("Tag Error: " + e.ToString());
}
finally
{
ndef.Close();
OnTagConnected?.Invoke(null, EventArgs.Empty);
}
}
}