+
+
+
@@ -144,11 +162,10 @@
-
-
+
@@ -178,13 +195,13 @@
-
+
-
+
-
+
@@ -276,41 +293,41 @@
-
+
-
-
-
-
-
+
+
-
-
+
+
-
+
-
+
-
-
+
+
+
+
+
-
+
-
-
+
+
diff --git a/README.md b/README.md
index 052dcbf..4a94c28 100644
--- a/README.md
+++ b/README.md
@@ -141,6 +141,26 @@ If your app **requires** NFC, you can add the following to only allow it to be d
If you're new to NFC you may come to expect a lot of `readNFC()` calls, but instead you see `readNDEF()` and `NDEFMessage`. NDEF is just a formatting standard the tags can be encoded in. There are other encodings than NDEF, but NDEF is the most common one. Currently NFC in Flutter only supports NDEF formatted tags.
+## Host Card Emulation
+
+NFC in Flutter supports reading from emulated host cards, however only on Android as Apple doesn't allow it on iOS.
+
+To read from emulated host cards, you need to do a few things.
+
+- Call `readNDEF()` with the `readerMode` argument set to an instance of `NFCDispatchReaderMode`.
+- Insert the following `` in your `AndroidManifest.xml` activity:
+
+```xml
+
+
+
+
+```
+
+### ⚠️ Multiple reader modes
+
+If you start a `readNDEF()` stream a `NFCDispatchReaderMode` while another stream is active with the `NFCNormalReaderMode`, it will throw a `NFCMultipleReaderModesException`.
+
## Platform differences
When you call `readNDEF()` on iOS, Core NFC (the iOS framework that allows NFC reading) opens a little window. On Android it just starts listening for NFC tag reads in the background.
diff --git a/android/src/main/java/me/andisemler/nfc_in_flutter/NfcInFlutterPlugin.java b/android/src/main/java/me/andisemler/nfc_in_flutter/NfcInFlutterPlugin.java
index 475e599..55cde67 100644
--- a/android/src/main/java/me/andisemler/nfc_in_flutter/NfcInFlutterPlugin.java
+++ b/android/src/main/java/me/andisemler/nfc_in_flutter/NfcInFlutterPlugin.java
@@ -1,6 +1,8 @@
package me.andisemler.nfc_in_flutter;
import android.app.Activity;
+import android.app.PendingIntent;
+import android.content.Intent;
import android.nfc.FormatException;
import android.nfc.NdefMessage;
import android.nfc.NdefRecord;
@@ -22,18 +24,23 @@
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result;
+import io.flutter.plugin.common.PluginRegistry;
import io.flutter.plugin.common.PluginRegistry.Registrar;
/**
* NfcInFlutterPlugin
*/
-public class NfcInFlutterPlugin implements MethodCallHandler, EventChannel.StreamHandler, NfcAdapter.ReaderCallback {
- private static final String LOG_TAG = "NfcInFlutterPlugin";
+public class NfcInFlutterPlugin implements MethodCallHandler,
+ EventChannel.StreamHandler,
+ PluginRegistry.NewIntentListener,
+ NfcAdapter.ReaderCallback {
private final Activity activity;
private NfcAdapter adapter;
private EventChannel.EventSink events;
+ private String currentReaderMode = null;
+
/**
* Plugin registration.
*/
@@ -41,6 +48,7 @@ public static void registerWith(Registrar registrar) {
final MethodChannel channel = new MethodChannel(registrar.messenger(), "nfc_in_flutter");
final EventChannel tagChannel = new EventChannel(registrar.messenger(), "nfc_in_flutter/tags");
NfcInFlutterPlugin plugin = new NfcInFlutterPlugin(registrar.activity());
+ registrar.addNewIntentListener(plugin);
channel.setMethodCallHandler(plugin);
tagChannel.setStreamHandler(plugin);
}
@@ -56,7 +64,35 @@ public void onMethodCall(MethodCall call, Result result) {
result.success(nfcIsEnabled());
break;
case "startNDEFReading":
- startReading();
+ if (!(call.arguments instanceof HashMap)) {
+ result.error("MissingArguments", "startNDEFReading was called with no arguments", "");
+ return;
+ }
+ HashMap args = (HashMap) call.arguments;
+ String readerMode = (String) args.get("reader_mode");
+ if (readerMode == null) {
+ result.error("MissingReaderMode", "startNDEFReading was called without a reader mode", "");
+ return;
+ }
+
+ if (currentReaderMode != null && !readerMode.equals(currentReaderMode)) {
+ // Throw error if the user tries to start reading with another reading mode
+ // than the one currently active
+ result.error("NFCMultipleReaderModes", "multiple reader modes", "");
+ return;
+ }
+ currentReaderMode = readerMode;
+ switch (readerMode) {
+ case "normal":
+ startReading();
+ break;
+ case "dispatch":
+ startReadingWithForegroundDispatch();
+ break;
+ default:
+ result.error("NFCUnknownReaderMode", "unknown reader mode: " + readerMode, "");
+ return;
+ }
result.success(null);
break;
default:
@@ -77,6 +113,18 @@ private void startReading() {
adapter.enableReaderMode(activity, this, NfcAdapter.FLAG_READER_NFC_A, bundle);
}
+ private void startReadingWithForegroundDispatch() {
+ adapter = NfcAdapter.getDefaultAdapter(activity);
+ if (adapter == null) return;
+ Intent intent = new Intent(activity.getApplicationContext(), activity.getClass());
+ intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
+
+ PendingIntent pendingIntent = PendingIntent.getActivity(activity.getApplicationContext(), 0, intent, 0);
+ String[][] techList = new String[][]{};
+
+ adapter.enableForegroundDispatch(activity, pendingIntent, null, techList);
+ }
+
@Override
public void onListen(Object args, EventChannel.EventSink eventSink) {
events = eventSink;
@@ -85,6 +133,7 @@ public void onListen(Object args, EventChannel.EventSink eventSink) {
@Override
public void onCancel(Object args) {
events = null;
+ currentReaderMode = null;
}
@Override
@@ -95,25 +144,19 @@ public void onTagDiscovered(Tag tag) {
return;
}
try {
- final Map result = new HashMap<>();
- List