我希望我能正确解释这一点。如果我做不好,请原谅我。
我有适用于Android的Xamarin NFC应用程序。你登录应用程序,触摸NFC卡,它读取卡上的信息,然后触摸按钮移动到新的意图,然后在该视图上你可以输入内容,点击卡,它应该写入卡片。
在最后一个视图中实际发生的事情是当你点击卡片刷新完全相同的视图时,然后再次点击它,然后才会写入NFC卡。
所以我认为我需要做的是在必须写入NFC卡的视图上停止NFC感应 - 它应该只处于写入模式,而不是处于读取模式。
非常感谢任何想法,谢谢。
第一次点击卡时,不会调用OnNewIntent。
编辑 - 添加代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.Nfc;
using Android.Nfc.Tech;
using Android.Preferences;
using Java.IO;
using System.Threading.Tasks;
using System.Net.Http;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
namespace [removed]
{
[Activity(Label = "Update Card")]
public class NfcWriter : Activity
{
public static readonly string PREFERENCE_FILENAME = "[removed]";
public static readonly string CLIENTID = "CLIENTID";
public static readonly string CLIENTUSERID = "CLIENTUSERID";
public static readonly string EMAILADDRESS = "EMAILADDRESS";
public static readonly string CARDID = "CARDID";
public static readonly string USERID = "USERID";
public static readonly string BALANCE = "BALANCE";
public const string ViewApeMimeType = "application/[removed]";//"application/[removed]";
private bool _inWriteMode;
private NfcAdapter _nfcAdapter;
private TextView _textView;
private Button _writeTagButton;
private AutoCompleteTextView _textEmail;
public static readonly string Tag = "NFC Writer";
public static string uuid = "";
private TextView _textCard;
private EditText _textAmount;
private static string cardID;
private static double balance;
private static double newBalance;
private TextView _txtCard;
private TextView _txtBalance;
private TextView _txtProduct;
private TextView _txtTotalPrice;
private static string layout;
private double amount = 0.0f;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
var c = (Context)this;
// get the nfc device adapter
_nfcAdapter = NfcAdapter.GetDefaultAdapter(this);
var allxsSettings = c.GetSharedPreferences(PREFERENCE_FILENAME, FileCreationMode.Private);
layout = allxsSettings.GetString("Layout", "Registration");
if (layout == "Registration")
{
SetContentView(Resource.Layout.writer);
if (Intent == null)
{
return;
}
_writeTagButton = FindViewById<Button>(Resource.Id.write_tag_button);
_writeTagButton.Click += WriteTagButtonOnClick;
_textView = FindViewById<TextView>(Resource.Id.text_view);
_textEmail = FindViewById<AutoCompleteTextView>(Resource.Id.EmailID);
_textEmail.Text = "";
}
if (layout == "CashLoad")
{
//_inWriteMode = true;
SetContentView(Resource.Layout.LoadCash);
if (Intent == null)
{
return;
}
_writeTagButton = FindViewById<Button>(Resource.Id.btnLoadCash);
_writeTagButton.Click += WriteTagButtonOnClick;
_textView = FindViewById<TextView>(Resource.Id.text_view);
_textAmount = FindViewById<EditText>(Resource.Id.txtCash);
_textCard = FindViewById<TextView>(Resource.Id.txtCardId);
cardID = allxsSettings.GetString (CARDID, "");
var tempBalance = allxsSettings.GetFloat(BALANCE, 0.0f);
balance = Convert.ToDouble(tempBalance);
_textCard.Text = cardID;
_textAmount.Text = "";
}
if (layout == "Sale") {
//_inWriteMode = true;
SetContentView(Resource.Layout.Sale);
if (Intent == null)
{
return;
}
_writeTagButton = FindViewById<Button>(Resource.Id.btnSale);
_writeTagButton.Click += WriteTagButtonOnClick;
_textView = FindViewById<TextView>(Resource.Id.text_view);
_txtBalance= FindViewById<TextView>(Resource.Id.txtCash);
_txtCard = FindViewById<TextView>(Resource.Id.txtCardId);
_txtProduct=FindViewById<TextView>(Resource.Id.txtProduct);
_txtTotalPrice=FindViewById<TextView>(Resource.Id.txtPrice);
cardID = allxsSettings.GetString (CARDID, "");
var tempBalance = allxsSettings.GetFloat (BALANCE, 0.0f);
balance = Convert.ToDouble(tempBalance);
_txtCard.Text = cardID;
_txtBalance.Text = balance.ToString("0.00");
Product productRow = null;
decimal totalAmount = 0;
_txtProduct.Text = "";
foreach (var salesRow in SalesManager.GetSaless()) {
productRow = ProductManager.GetProduct (salesRow.ProductID);
totalAmount += Convert.ToDecimal (salesRow.TotalAmount);
if (_txtProduct.Text.Length != 0)
_txtProduct.Text += "\n";
_txtProduct.Text += salesRow.NoOfUnits + " x " + productRow.ProductName + " @ " + productRow.UnitPrice.ToString ("0.00");
}
_txtTotalPrice.Text = totalAmount.ToString("0.00");
// determine the new card balance
newBalance = balance - Convert.ToDouble (totalAmount);
if (newBalance < 0) {
// we don't have enough money to buy
_txtTotalPrice.Text += " INSUFFICIENT FUNDS";
toast ("INSUFFICIENT FUNDS - NO SALE");
}
}
}
/// <summary>
/// This method is called when an NFC tag is discovered by the application.
/// </summary>
/// <param name="intent"></param>
protected override void OnNewIntent(Intent intent)
{
_inWriteMode = true;
if (_inWriteMode)
{
//_inWriteMode = false;
var c = (Context)this;
var allxsSettings = c.GetSharedPreferences(PREFERENCE_FILENAME, FileCreationMode.Private);
var tag = intent.GetParcelableExtra(NfcAdapter.ExtraTag) as Tag;
if (tag == null)
{
return;
}
Card card = new Card ();
if (layout == "Registration") {
card.CardID = _textEmail.Text;
card.Amount = 0.0f;
}
if (layout == "CashLoad") {
card.CardID = _textCard.Text;
card.Amount = balance;
}
if (layout == "Sale") {
// no write allowed if there is no money
if (newBalance < 0) {
toast ("INSUFFICIENT FUNDS - NO SALE");
return;
}
var cardID = allxsSettings.GetString (CARDID, "");
var tempBalance = allxsSettings.GetFloat (BALANCE, 0.0f);
var balance = Convert.ToDouble(tempBalance);
var clientUserId = allxsSettings.GetInt (CLIENTUSERID, 0);
card.CardID = cardID;
card.Amount = newBalance;
}
BinaryFormatter payload = new BinaryFormatter();
MemoryStream ms = new MemoryStream();
payload.Serialize(ms, card);
var mimeBytes = Encoding.ASCII.GetBytes(ViewApeMimeType);
var cardRecord = new NdefRecord(NdefRecord.TnfMimeMedia, mimeBytes, new byte[0], ms.ToArray());
var ndefMessage = new NdefMessage(new[] { cardRecord });
bool isWritten = false;
if (!TryAndWriteToTag(tag, ndefMessage))
{
// Maybe the write couldn't happen because the tag wasn't formatted?
if (TryAndFormatTagWithMessage(tag, ndefMessage))
isWritten = true;
}
else
{
isWritten = true;
}
// if we did write to the card then we must update the server api (this is where the transaction should be stored locally and updated later)
if (isWritten)
{
if (layout == "Registration")
{
// this is a new card - we don't know who the user is at this time but send the card registration to the system
ApiCardRegistration(card.CardID);
}
if (layout == "CashLoad")
{
// tell the api that we have loaded cash
ApiCardLoadCash(card.CardID, amount);
}
if (layout == "Sale")
{
// we have written the sale amount to the card, now write to the server
ApiCardLoadProducts (card.CardID);
}
}
ISharedPreferencesEditor prefEditor = allxsSettings.Edit();
prefEditor.PutString("Layout", "");
prefEditor.Apply();
prefEditor.Commit();
}
}
protected override void OnPause()
{
base.OnPause();
// App is paused, so no need to keep an eye out for NFC tags.
if (_nfcAdapter != null)
_nfcAdapter.DisableForegroundDispatch(this);
}
private void DisplayMessage(string message)
{
_textView.Text = message;
//Log.Info(Tag, message);
}
/// <summary>
/// Identify to Android that this activity wants to be notified when
/// an NFC tag is discovered.
/// </summary>
private void EnableWriteMode()
{
_inWriteMode = true;
// Create an intent filter for when an NFC tag is discovered. When
// the NFC tag is discovered, Android will u
var tagDetected = new IntentFilter(NfcAdapter.ActionTagDiscovered);
var filters = new[] { tagDetected };
// When an NFC tag is detected, Android will use the PendingIntent to come back to this activity.
// The OnNewIntent method will invoked by Android.
var intent = new Intent(this, GetType()).AddFlags(ActivityFlags.SingleTop);
var pendingIntent = PendingIntent.GetActivity(this, 0, intent, 0);
if (_nfcAdapter == null)
{
var alert = new AlertDialog.Builder(this).Create();
alert.SetMessage("NFC is not supported on this device.");
alert.SetTitle("NFC Unavailable");
alert.SetButton("OK", delegate
{
_writeTagButton.Enabled = false;
_textView.Text = "NFC is not supported on this device.";
});
alert.Show();
}
else
_nfcAdapter.EnableForegroundDispatch(this, pendingIntent, filters, null);
}
/// <summary>
///
/// </summary>
/// <param name="tag"></param>
/// <param name="ndefMessage"></param>
/// <returns></returns>
private bool TryAndFormatTagWithMessage(Tag tag, NdefMessage ndefMessage)
{
var format = NdefFormatable.Get(tag);
if (format == null)
{
DisplayMessage("Tag does not appear to support NDEF format.");
}
else
{
try
{
format.Connect();
format.Format(ndefMessage);
DisplayMessage("Tag successfully written.");
return true;
}
catch (System.IO.IOException ioex)
{
var msg = "There was an error trying to format the tag.";
DisplayMessage(msg);
//Log.Error(Tag, ioex, msg);
}
}
return false;
}
private void WriteTagButtonOnClick(object sender, EventArgs eventArgs)
{
var view = (View)sender;
if (view.Id == Resource.Id.write_tag_button)
{
DisplayMessage("Touch and hold the tag against the phone to write.");
EnableWriteMode();
}
if (view.Id == Resource.Id.btnLoadCash)
{
if (_textAmount.Text.Trim().Length == 0)
toast("Please enter Amount.");
else
{
if (_textCard.Text.Trim().Length == 0)
{
toast("Please enter Card Number");
return;
}
amount = 0;
try
{
amount = Convert.ToDouble(_textAmount.Text.Trim());
}
catch
{
toast("Invalid Amount");
return;
}
if (cardID == "")
cardID = _textCard.Text;
balance += amount;
DisplayMessage("Touch and hold the tag against the phone to write.");
EnableWriteMode();
}
}
if (view.Id == Resource.Id.btnSale) {
DisplayMessage("Touch and hold the tag against the phone to write.");
EnableWriteMode();
}
}
/// <summary>
/// This method will try and write the specified message to the provided tag.
/// </summary>
/// <param name="tag">The NFC tag that was detected.</param>
/// <param name="ndefMessage">An NDEF message to write.</param>
/// <returns>true if the tag was written to.</returns>
private bool TryAndWriteToTag(Tag tag, NdefMessage ndefMessage)
{
// This object is used to get information about the NFC tag as
// well as perform operations on it.
var ndef = Ndef.Get(tag);
if (ndef != null)
{
ndef.Connect();
// Once written to, a tag can be marked as read-only - check for this.
if (!ndef.IsWritable)
{
DisplayMessage("Tag is read-only.");
}
// NFC tags can only store a small amount of data, this depends on the type of tag its.
var size = ndefMessage.ToByteArray().Length;
if (ndef.MaxSize < size)
{
DisplayMessage("Tag doesn't have enough space.");
}
ndef.WriteNdefMessage(ndefMessage);
DisplayMessage("Succesfully wrote tag.");
return true;
}
return false;
}
答案 0 :(得分:1)
我通过改变NfcWriter类意图的启动方式解决了这个问题。上面的代码不是问题所在,因为除了创建意图的方式之外我从来没有做过任何更改。
我替换了#34;这个&#34;使用&#34; Application.ApplicationContext&#34;并将标志设置为&#34; NewTask&#34;在调用代码中,它变成了这个......
Android.Content.Intent intent = new Intent(Application.ApplicationContext, typeof(NfcWriter));
intent.AddFlags(ActivityFlags.NewTask);
StartActivity(intent);
我希望这可以帮助别人。
我从Xamarin支持人员Brendan那里获得了一些聪明的帮助,他引导我从交互中创建NFC日志,然后研究日志以找出问题所在。
对我最有帮助的是在NFC日志中,发现了这个错误 - &#34;从非活动上下文调用的startActivity&#34;以及大量的反复试验。
要访问NFC日志,您可以按照以下步骤操作:
收集所有&#39; adb logcat&#39;日志
adb logcat -d -vtime&gt; C:\用户\%USERNAME%\桌面\ nfc_logcat.txt
adb logcat -d -vtime -bradio&gt; C:\用户\%USERNAME%\桌面\ nfc_radio.txt
adb logcat -d -vtime -bevents&gt; C:\用户\%USERNAME%\桌面\ nfc_events.txt
在Windows上,使用Xamarin安装程序时adb
的默认安装位置为:
C:\ Users \%USERNAME%\ AppData \ Local \ Android \ android-sdk \ platform-tools \ adb.exe