semlette / nfc_in_flutter

Cross-platform flutter plugin for reading and writing NFC tags. Not maintained anymore - not looking for new maintainer, fork instead.
MIT License
120 stars 119 forks source link

How to stop showing "New tag scanned" page on android #50

Open ryanhz opened 4 years ago

ryanhz commented 4 years ago

On android (Samsung S8), when successfully scan a NFC tag with text record, there is a seperate view showing "New tag scanned" with the tag message, how can I stop it from showing?

It turns out this is the system's default behaviour of showing whatever user scan

KrunalRGandhi commented 4 years ago

hello, any update on this? How can we prevent Android native app or any other app from reading NFC tag when tag is being read by Flutter app using this plugin?

I have seen ways to do this in Android apps using enableForegroundDispatch. I am not sure if this plugin uses that internally or is there another way for Flutter to prevent other apps on the device from getting the read NFC tag when a flutter app with this plugin is reading NFC tags.

Thanks.

jamesmcarthur115555 commented 4 years ago

Plus one for me ! Any solution

KrunalRGandhi commented 4 years ago

I found that api.dart file in this plugin has method to use ForegroundDispatch instead of readerMode. I tried using that along with appropriate intent filter in AndroidManifest.xml and it did work, NFC content was passed only to my app.

Currently the plugin hardcodes to using ReaderMode assuming this will only pass the discovered NFC tag to the app. However it seems on Android 10, that is not true. See discussion here https://stackoverflow.com/questions/33633736/whats-the-difference-between-enablereadermode-and-enableforegrounddispatch

ryanhz commented 4 years ago

Hmm, that is a good starter. How to get rid of the "No supported application for this NFC tag" toast on Android 10?

James-A-White commented 4 years ago

Plus one for me as well. This can be very annoying to customers.

ElectricCookie commented 4 years ago

Calling read operations with the readerMode NFCDispatchReaderMode() causes the plugin to use the NFC Adapter in Foreground mode (internally it calls adapter.enableForegroundDispatch(activity, pendingIntent, null, techList);) which prevents the popup.

Example:

NDEFMessage message = await NFC
        .readNDEF(once: true, readerMode: NFCDispatchReaderMode())
        .first;

🚀

KrunalRGandhi commented 4 years ago

One way to avoid the default "New tag scanned" popup is to run a continuous background read when the application starts/resumes (application is in the foreground). Keep ignoring any tags read when they are not desired. When desired on a particular page process the tag read. Or one can stop the continuous background read started when the application started/resumed and start another one-time tag read operation when desired at a certain place in the application. Once done, again start the background read so that undesired tags are not read by system or any other application on the phone.

Note: in both cases, one needs to read the tags with NFCDispatchReaderMode to tell Android that any NFC tag detected needs to be passed to this application only.

The current plugin hardcodes the use of Normal mode, so one can clone the plugin into a separate repository and make changes to use the desired mode and use this new repository in the project.

Here is an example code: Call _readNFCAndroid when the app starts or resumes. Call _stopNFC when app is closed or paused. Also, when on a particular page or based on user action need to read the tag just call _stopNFC and do a local read using a similar method below (with parameter once set to true) and after reading call _readNFCAndroid to again start reading in the background. This will allow control to read and process when desired and read and ignore when not desired while the application is in the foreground.

Note: I have cloned the plugin and created a new method in it "readNDEFDispatch". This one is the same as the existing one "readNDEF" except for this new one uses NFCDispatchReaderMode.

StreamSubscription _nfcStream; _readNFCAndroid() async { NDEFMessage nfcTag;

try {
  /// readNDEF starts listening for NDEF formatted tags. Any non-NDEF formatted
  /// tags will be filtered out. So no need to check for NDEF format.

  // ignore: cancel_subscriptions
  StreamSubscription<NDEFMessage> subscription = NFC
      .readNDEFDispatch(
    once: false, // keep reading!!
    throwOnUserCancel: true,
  ).listen((tag) {
    // NFC read success
    nfcTag = tag;
  },
      // When the stream is done, remove the subscription from state
      onDone: () async {
        _nfcStream = null;
        if (nfcTag.isEmpty || nfcTag.payload == null) {
          // invalid tag. Ignore it!
        } else {
          // Its a valid tag. Ignore it!
        }
      },
      // Errors are unlikely to happen on Android unless the NFC tags are
      // poorly formatted or removed too soon, however on iOS at least one
      // error is likely to happen. NFCUserCanceledSessionException will
      // always happen unless you call readNDEF() with the `throwOnUserCancel`
      // argument set to false.
      // NFCSessionTimeoutException will be thrown if the session timer exceeds
      // 60 seconds (iOS only).
      // And then there are of course errors for unexpected stuff. Good fun!
      onError: (e) {
        stopNFC();
        checkAndStartNFCReading();
      });

  // set _nfcStream with this subscription so that it can be cancelled.
  _nfcStream = subscription;
} catch (e) {
  stopNFC();
  checkAndStartNFCReading();
}

}

_stopNFC() { _nfcStream?.cancel(); _nfcStream = null; }

ahmedmirza994 commented 3 years ago

@Override protected void onResume() { super.onResume(); NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this); Intent intent = new Intent(this, getClass()); intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); PendingIntent pendingIntent = PendingIntent.getActivities(this, 0, new Intent[] { intent }, 0); if (nfcAdapter == null) return; String[][] techList = new String[][] {}; nfcAdapter.enableForegroundDispatch(this, pendingIntent, null, null); }

@Override
protected void onPause() {
    super.onPause();
    NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this);
    if (nfcAdapter == null)
        return;
    nfcAdapter.disableForegroundDispatch(this);
}

add this in your main activity class. this will prevent android default nfc popup screen

mazensabouni commented 3 years ago

Hello, Could some one tell if there a 100% worked solution of these and how to apply it? Thanks

ZippyRainbow commented 3 years ago

If you use the once: false option that should do the job, but I found that by using a URI, you can use the background NFC function as well to get it to point to the app to prevent it from popping up the New Tag Scanned when the multi scan is not active.

mazensabouni commented 3 years ago

I'm scanning the tag once through my to do a certain action , but the problem is that it scanned once and do the action then when you get the phone away from the tag the background NFC detect the tag again and open the content of it , the content in my case is a haskey , I'll try the once : false as in my case its only one tag no matter to read it again

batoul-alani commented 1 year ago

is there any solution for this issue?

islom9797 commented 10 months ago

https://stackoverflow.com/questions/76443776/how-can-i-prevent-the-default-new-tag-scanned-pop-up-using-the-nfc-manager-p/77357058#77357058 please check this link.it worked for me