0

I am currently working on a simple app, which scans an NFC tag and reads the data from it. To implement it, I followed this example here.

For testing, I am using a real android device (Samsung Galaxy J6) and a Mifare NFC card.

At the launch of the app, everything seems fine, the NfcManager has been successfully started, the tag event has been registered (using NfcManager.registerTagEvent),but the problem occurs when requestTechnology has been called and the NFC card scanned.

The difference I noticed is regarding the intent in Android: before running requestTechnology and scanning the card against the phone, the intent and the action attached to it look like this => the action is on the main thread.

After that, the intent and the action look like this.

It seemed strange to me that the action has changed from the main thread.

The Android code is exactly like given in the link above and the code in React Native looks like this:

 _read = async () => {
    try {
      const enabled = await NfcManager.isEnabled();
      console.warn('Enabled: ', enabled);

      await NfcManager.registerTagEvent((tag) => {
        console.warn('Tag Discovered', tag);
      }, 'Hold your device over the tag', true);
  
      let tech = Platform.OS === 'ios' ? NfcTech.MifareIOS : [NfcTech.MifareClassic, NfcTech.NfcA];
      let resp = await NfcManager.requestTechnology(tech);

      let tag = await NfcManager.getTag()
        .then(() => { console.warn('Tag: ', tag)})
        .catch((err) => console.warn('Tag error: ', err));
     
      {...}

      // this._cleanUp();
    } catch (ex) {
      console.warn(ex);
      this._cleanUp();
    }
  }

Besides that, the method requestTechnology is resolved only if the app is brought to the background and then again to the foreground right away. That also seems strange ...

Does anyone have any idea how to solve these issues and get the NFC card reading process up and running?

I appreciate your help!

Yennefer
  • 5
  • 4

1 Answers1

0

I'm not sure why you are looking at the Intent Action as it is of no significance to NFC really.

Some background of how Android handles NFC should help explain it.

In Android all Tag detection is handled by a System NFC service/App.

When you App is not running and a NFC Tag is detected the System Service works out if any App has requested to be started when that type of Tag is seen. It then crafts an Intent to get the System Launcher to launch the main Activity of you app and bundles information about the NFC data in the extras section of the Intent for the System Launcher to pass on in the Intent to your app at Launch time.

When you are doing requestTechnology your App is already running and you are telling the System NFC Service to pass the NFC data directly to your App, the System Launcher does not need to be involved as your App is already running.

Now Android has two methods of passing this data directly to your running App, enableForegroundDispatch or the later and much better enableReaderMode.

You configured react-native-nfc-manager to use the older enableForegroundDispatch which tells the system NFC service to send the Tag details directly to your running Activity. So it does not need to add an Action to tell the system Launcher what to do. But to deliver that Intent with the extras contain data about the Tag directly to your App, the only way for it to do that is to basically restart your App which causes a Pause and Resume.

But react-native-nfc-manager handles all this for you, so you should not need to worry about what is in the Intent

Note you can configure react-native-nfc-manager to use enableReaderMode and instead of overloading an Intent to deliver this data to you, if basically creates a Thread in your running App and gives the Thread the Tag data directly and thus does not need to pause and resume your App (plus you get more control of things like NFC detection sound with this newer method)

So overall the behaviour you are seeing is expected and normal and nothing you should be concerned about or have a problem with.

Note iOS handles this completely differently but again react-native-nfc-manager handles this via it's iOS specific methods.

Andrew
  • 8,198
  • 2
  • 15
  • 35
  • that's a great explanation, thanks! :) you're right, I am using `enableForegroundDispatch` and when `requestTechnology` is called, the methods `onHostPause` and `onHostResume` are also called, so I assume that's alright. What I do not understand is why doesn't the app actually read the NFC. As I mentioned, I have to bring the app in the background and then right away back in foreground for it to call the method `getTag`. This is what actually bothers me ... – Yennefer Jan 12 '22 at 07:02
  • May be related to https://github.com/revtel/react-native-nfc-manager/issues/423 ?? there seems to be a scenario where this package does not correctly configure `enableForegroundDispatch` and manually pausing and resuming the App by sending it to the background would fix it. – Andrew Jan 12 '22 at 10:42
  • I think this is exactly what I need to do, to send it to background first, in order for the app to work. But this cannot be the final solution, since the user shouldn't have to close and reopen the app in order for it work. On the other hand, even if the tag is scanned after the app is in the foreground once more, it's not scanned correctly, since the app throws an error... – Yennefer Jan 12 '22 at 13:39
  • This is fixable in `react-native-nfc-manager`, I added a comment in the bug on how to fix it. – Andrew Jan 12 '22 at 13:45
  • From `Context` https://developer.android.com/reference/android/content/Context#registerReceiver(android.content.BroadcastReceiver,%20android.content.IntentFilter). In my Native Android App, it's in `onCreate` of the Activity (Activity class is an indirect subclass of Context) – Andrew Jan 12 '22 at 19:51
  • aparently the BroadcastReceiver was already in the code (see class NfcManager.java line 1110) – Yennefer Jan 12 '22 at 20:31
  • I think the problem is here ` String action = intent.getAction(); Log.d(LOG_TAG, "action " + action); if (action == null) { return null; }`. After scanning the tag, onHostResume is called, then onNewIntent and here the action is null, thus the method returns null and it does not go further (the intent has now a flag 0x34000000) – Yennefer Jan 12 '22 at 20:47
  • Yes I see the BroadcastReceiver my understanding of JavaScript and this module is not great but to me is that it just exposes that event to the Javascript and does nothing with it, it should enable the foregroundDispatch if that is configured. May be the module designer is expecting you to do that in the Javascript instead of the native code. – Andrew Jan 12 '22 at 21:12
  • It does enable foreground dispatch, the method `enableDisableForegroundDispatch` is called twice: once with false, I think that's why the intent.action is null and after that with true. – Yennefer Jan 13 '22 at 19:00
  • Calling `enableDisableForegroundDispatch` = `false` is disable foreground detection. It needs to be called twice with a value of `true`. Once when first calling `registerTagEvent` which in this scenario will fail to actually enable it because Nfc is turned off, then again when NFC is actually turned on without pausing the App. – Andrew Jan 13 '22 at 20:21