相关文章推荐
Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

I'm asking the following question for advice, I've had a look online (and similar questions here on stackoverflow) with no solution that works for me.

I'm writing an Android app (for full disclosure I'm doing it in Xamarin - but the technology should be irrelevant) and all I want it to do is to show an alert / toast message when an NFC code has been scanned in. If I have the app open and I put my NFC tag against my phone the alert displays as expected. When the app has been closed and I put the NFC tag against my phone the app opens but this is as far as it goes.

I'm fairly new to Android development (I've previously been very generic when creating Android apps through Xamarin and not really using device features such as NFC / Bluetooth) so if I'm missing something fairly obvious I do apologize.

using System.Text;
using Android.App;
using Android.Content;
using Android.Nfc;
using Android.OS;
using Android.Support.V7.App;
namespace Android.Demo
    [Activity(Label = "@string/app_name", Theme = "@style/AppTheme.NoActionBar", MainLauncher = true, LaunchMode = Content.PM.LaunchMode.SingleInstance)]
    [IntentFilter(new[] { NfcAdapter.ActionNdefDiscovered }, Categories = new[] { "android.intent.category.DEFAULT" }, DataMimeType = "*/*")]
    public class MainActivity : AppCompatActivity
        private NfcAdapter _nfcAdapter;
        private PendingIntent _pendingIntent;
        private string[][] _techList = new string[][]{
                     new[] { "android.nfc.tech.NdefFormatable" } ,
                     new [] { "android.nfc.tech.NfcA" } ,
                     new [] { "android.nfc.tech.Ndef" },
                     new [] { "android.nfc.tech.Ndef" }};
        protected override void OnCreate(Bundle savedInstanceState)
            _nfcAdapter = NfcAdapter.GetDefaultAdapter(this);
            base.OnCreate(savedInstanceState);
            Xamarin.Essentials.Platform.Init(this, savedInstanceState);
            SetContentView(Resource.Layout.activity_main);
            _pendingIntent = PendingIntent.GetActivity(this, 0, Intent, 0);
            Android.Support.V7.Widget.Toolbar toolbar = FindViewById<Android.Support.V7.Widget.Toolbar>(Resource.Id.toolbar);
            SetSupportActionBar(toolbar);
        protected override void OnPause()
            base.OnPause();
            if (_nfcAdapter != null && _nfcAdapter.IsEnabled)
                _nfcAdapter.DisableForegroundDispatch(this);
        protected override void OnResume()
            base.OnResume();
            // doStuff();
            _nfcAdapter.EnableForegroundDispatch(this, _pendingIntent, new[] { new IntentFilter(NfcAdapter.ActionNdefDiscovered), new IntentFilter(NfcAdapter.ActionTechDiscovered), new IntentFilter(NfcAdapter.ActionTagDiscovered), new IntentFilter(NfcAdapter.ActionNdefDiscovered) }, _techList);
        protected override void OnNewIntent(Intent intent)
            var tag = intent.GetParcelableExtra(NfcAdapter.ExtraTag) as Tag;
            if (tag != null)
                // First get all the NdefMessage
                var rawMessages = intent.GetParcelableArrayExtra(NfcAdapter.ExtraNdefMessages);
                if (rawMessages != null)
                    var msg = (NdefMessage)rawMessages[0];
                    // Get NdefRecord which contains the actual data
                    var record = msg.GetRecords()[0];
                    if (record != null)
                        if (record.Tnf == NdefRecord.TnfWellKnown) // The data is defined by the Record Type Definition (RTD) specification available from http://members.nfc-forum.org/specs/spec_list/
                            // Get the transfered data
                            var data = Encoding.ASCII.GetString(record.GetPayload());
                            var alert = new App.AlertDialog.Builder(this).Create();
                            alert.SetMessage(data);
                            alert.SetTitle("NFC Tag Located");
                            alert.Show();

Thanks

Normally you should use onNewIntent(Intent intent) just to set the last intnet you have. I would write your code in the following way:

using System.Text;
using Android.App;
using Android.Content;
using Android.Nfc;
using Android.OS;
using Android.Support.V7.App;
namespace Android.Demo
[Activity(Label = "@string/app_name", Theme = "@style/AppTheme.NoActionBar", MainLauncher = true, LaunchMode = Content.PM.LaunchMode.SingleInstance)]
[IntentFilter(new[] { NfcAdapter.ActionNdefDiscovered }, Categories = new[] { "android.intent.category.DEFAULT" }, DataMimeType = "*/*")]
public class MainActivity : AppCompatActivity
    private NfcAdapter _nfcAdapter;
    private PendingIntent _pendingIntent;
    private string[][] _techList = new string[][]{
                 new[] { "android.nfc.tech.NdefFormatable" } ,
                 new [] { "android.nfc.tech.NfcA" } ,
                 new [] { "android.nfc.tech.Ndef" },
                 new [] { "android.nfc.tech.Ndef" }};
    protected override void OnCreate(Bundle savedInstanceState)
        _nfcAdapter = NfcAdapter.GetDefaultAdapter(this);
        base.OnCreate(savedInstanceState);
        Xamarin.Essentials.Platform.Init(this, savedInstanceState);
        SetContentView(Resource.Layout.activity_main);
        _pendingIntent = PendingIntent.GetActivity(this, 0, Intent, 0);
        Android.Support.V7.Widget.Toolbar toolbar = FindViewById<Android.Support.V7.Widget.Toolbar>(Resource.Id.toolbar);
        SetSupportActionBar(toolbar);
    protected override void OnPause()
        base.OnPause();
        if (_nfcAdapter != null && _nfcAdapter.IsEnabled)
            _nfcAdapter.DisableForegroundDispatch(this);
    protected override void OnResume()
        base.OnResume();
        if(isNfcIntent(getIntent())){
            processNfcIntent(getIntent());
        // doStuff();
        _nfcAdapter.EnableForegroundDispatch(this, _pendingIntent, new[] { new IntentFilter(NfcAdapter.ActionNdefDiscovered), new IntentFilter(NfcAdapter.ActionTechDiscovered), new IntentFilter(NfcAdapter.ActionTagDiscovered), new IntentFilter(NfcAdapter.ActionNdefDiscovered) }, _techList);
    protected override void OnNewIntent(Intent intent)
        setIntent(intent);
processIntent(Intent intent){
var tag = intent.GetParcelableExtra(NfcAdapter.ExtraTag) as Tag;
         // First get all the NdefMessage
            var rawMessages = intent.GetParcelableArrayExtra(NfcAdapter.ExtraNdefMessages);
            if (rawMessages != null)
                var msg = (NdefMessage)rawMessages[0];
                // Get NdefRecord which contains the actual data
                var record = msg.GetRecords()[0];
                if (record != null)
                    if (record.Tnf == NdefRecord.TnfWellKnown) // The data is defined by the Record Type Definition (RTD) specification available from http://members.nfc-forum.org/specs/spec_list/
                        // Get the transfered data
                        var data = Encoding.ASCII.GetString(record.GetPayload());
                        var alert = new App.AlertDialog.Builder(this).Create();
                        alert.SetMessage(data);
                        alert.SetTitle("NFC Tag Located");
                        alert.Show();

so In this way processNfcIntent(Intent intent) will be called in the starting of the app if it starts because of touching NFC tag and it will be called if a onNewIntent(Intent intent) is called.

The android will call onResume() always after onNewIntent(Intent intent). the function isNfcIntent(Intent intent) should return false if the intent is not nfc intent for example :

private boolean isNfcIntent(Intent intent){
var tag = intent.GetParcelableExtra(NfcAdapter.ExtraTag) as Tag;
    return tag != null;

I have a App that reads Tags when it is running and is registered to process Tag's so that it gets started up when it is not running.

What you are probably missing is that when you are running the Intent with the Tag a data in it is passed to OnNewIntent but when you are not running that Intent is passed to onCreate.

There I do something similar to this:-

protected override void OnCreate(Bundle savedInstanceState) // Other onCreate Stuff // Get any Intent the app was started with var mIntent = getIntent(); // Check that the Intent contains details about NFC data var tag = mIntent.GetParcelableExtra(NfcAdapter.ExtraTag) as Tag; if (tag != null) OnNewIntent(mIntent);

Note I don't do Xamarin, so not tested but I do similar in Java

Thank you, this worked absolutely perfectly (in c# there is a property Intent which does what getIntent() does so had to tweak this a little). Much appreciated – Chris Boot Feb 3, 2020 at 19:07

Thanks for contributing an answer to Stack Overflow!

  • Please be sure to answer the question. Provide details and share your research!

But avoid

  • Asking for help, clarification, or responding to other answers.
  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.

 
推荐文章