Catch onNewIntent() in flutter plugin class

1,514

Solution 1

Ok, I found the way which worked for me perfectly.

There was no need for onNewIntent().

As @chunhunghan mentioned, I implemented NfcAdapter.ReaderCallback. But to catch the triggering event I use onTagDiscovered(tag: Tag).

So it looks like:

class NfcFlutterPlugin(private var activity: Activity?) : MethodCallHandler, NfcAdapter.ReaderCallback, EventChannel.StreamHandler {
  private var mNfcAdapter: NfcAdapter? = null
  private var  mEventSink: EventChannel.EventSink? = null

  companion object {
    @JvmStatic
    fun registerWith(registrar: Registrar) {
      var nfcflutterPlugin = NfcFlutterPlugin(registrar.activity())
      val channel = MethodChannel(registrar.messenger(), "nfc_flutter")
      channel.setMethodCallHandler(nfcflutterPlugin)
      val eventChannel = EventChannel(registrar.messenger(), "nfcDataStream")
      eventChannel.setStreamHandler(nfcflutterPlugin)
    }
  }

  fun initializeNFCReading():Boolean {
    mNfcAdapter = NfcAdapter.getDefaultAdapter(activity)

    if(!checkNFCEnable())
      return false
    if (mNfcAdapter == null)
      return false

    val bundle = Bundle()
    mNfcAdapter?.enableReaderMode(activity, this, NfcAdapter.FLAG_READER_NFC_A, bundle)

    return true
  }

  private fun checkNFCEnable(): Boolean {
    return if (mNfcAdapter == null) {
      //mTvView.text = getString(R.string.tv_noNfc)
      false
    } else {
      mNfcAdapter!!.isEnabled
    }
  }

  override fun onMethodCall(call: MethodCall, result: Result) {
    if (call.method == "getPlatformVersion") {
      result.success("Android ${android.os.Build.VERSION.RELEASE}")
      return
    }
    if (call.method == "initializeNFCReading") {
      result.success(initializeNFCReading())
      return
    }

    result.notImplemented()

  }

  override fun onTagDiscovered(tag: Tag) {
    val ndef = Ndef.get(tag)
            ?: // tag is not in NDEF format; skip!
            return
    try {
      ndef.connect()
      val message = ndef.ndefMessage ?: return
      parserNDEFMessage(message)

    } catch (e: IOException) {
    } catch (e: FormatException) {
    }

  }


  private fun parserNDEFMessage(message: NdefMessage) {
    //parse message
    mEventSink?.success(parsedMessage)
  }

  override fun onListen(p0: Any?, eventSink: EventChannel.EventSink?) {
    mEventSink = eventSink
  }

  override fun onCancel(p0: Any?) {
    mEventSink = null
  }
}

Solution 2

Implement PluginRegistry.NewIntentListener for listening intent methods. Check here.

It has onNewIntent method. you can use it. Like,

class NfcforflutterPlugin(private var activity: Activity?) : MethodCallHandler, EventChannel.StreamHandler, PluginRegistry.NewIntentListener {
      ....................
      ....................
      override fun onNewIntent(intent:Intent):Boolean  {
            //handle data with intent
        return false;
     }
}
Share:
1,514
drek
Author by

drek

I am Android developer. Currently mostly on Java and little on Kotlin. Also I love doing cross platform apps on Flutter.

Updated on December 13, 2022

Comments

  • drek
    drek over 1 year

    Question title might be a bit confusing. I will try to explain more details.

    I am writing a flutter plugin to use NFC.

    I have example Android Activity that triggers onNewIntent() as it receives NDEF message. At this moment the message payload is ready to be used.

    class MainActivity : AppCompatActivity() {
        private var mNfcAdapter: NfcAdapter? = null
        private var mPendingIntent: PendingIntent? = null
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
    
            mNfcAdapter = NfcAdapter.getDefaultAdapter(this)
    
            mPendingIntent = PendingIntent.getActivity(
                    this, 0,
                    Intent(this, this.javaClass)
                        .addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0
                )
        }
    
        override fun onResume() {
            super.onResume()
            mNfcAdapter?.enableForegroundDispatch(this, mPendingIntent, null, null)
        }
    
        override fun onPause() {
            super.onPause()
            mNfcAdapter?.disableForegroundDispatch(this)
        }
    
        override fun onNewIntent(intent: Intent) {
            super.onNewIntent(intent)
            if (NfcAdapter.ACTION_NDEF_DISCOVERED == intent.action) {
                intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES)?.also { rawMessages ->
                    val messages: List<NdefMessage> = rawMessages.map { it as NdefMessage }
    
                    parseNDEFMessage(messages)
                }
            }
        }
    
        private fun parseNDEFMessage(messages: List<NdefMessage>) {
            //do parsing and display payload
        }
    
    

    I need to have same functionality in plugin class.

    Here is my plugin class

    class NfcforflutterPlugin(private var activity: Activity?) : MethodCallHandler, EventChannel.StreamHandler {
      private var mNfcAdapter: NfcAdapter? = null
      private var mPendingIntent: PendingIntent? = null
        private var  mEventSink: EventChannel.EventSink? = null
    
      companion object {
        @JvmStatic
        fun registerWith(registrar: Registrar) {
            var nfcforflutterPlugin = NfcforflutterPlugin(registrar.activity())
            val channel = MethodChannel(registrar.messenger(), "nfcforflutter")
            channel.setMethodCallHandler(nfcforflutterPlugin)
            val eventChannel = EventChannel(registrar.messenger(), "nfcforflutter")
            eventChannel.setStreamHandler(nfcforflutterPlugin)
        }
      }
    
      fun getNDEFMessage(): String{
        return "CALLED getNDEFMessage"
      }
    
      fun initializeNFCReading():Boolean {
        mNfcAdapter = NfcAdapter.getDefaultAdapter(activity)
    
        if(!checkNFCEnable())
                return false
        val intent = Intent(activity?.applicationContext, activity?.javaClass)
        intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)
    
        val pendingIntent = PendingIntent.getActivity(activity?.applicationContext, 0, intent, 0)
    
        mNfcAdapter?.enableForegroundDispatch(activity, pendingIntent, null, null)
            return true
      }
    
      private fun checkNFCEnable(): Boolean {
        return if (mNfcAdapter == null) {
          false
        } else {
          mNfcAdapter!!.isEnabled
        }
      }
    
      override fun onMethodCall(call: MethodCall, result: Result) {
        if (call.method == "getPlatformVersion") {
          result.success("Android ${android.os.Build.VERSION.RELEASE}")
          return
        }
        if (call.method == "getNDEFMessage") {
          result.success(getNDEFMessage())
          return
        }
          if (call.method == "initializeNFCReading") {
              result.success(initializeNFCReading())
              return
          }
    
        result.notImplemented()
    
      }
    
      override fun onListen(p0: Any?, eventSink: EventChannel.EventSink?) {
            mEventSink = eventSink
      }
    
      override fun onCancel(p0: Any?) {
      }
    

    SInce NfcforflutterPlugin is not an Activity, I need a triggering event in NfcforflutterPlugin class as onNewIntent() in Android Activity which will be invoked at the message discovering moment, so that I can run mEventSink.success(ndefMessage) and pass message to Flutter side.

    Any idea?

    • Abhay Koradiya
      Abhay Koradiya almost 5 years
      what is the issue ? you have messages list in activity which you can pass.
    • drek
      drek almost 5 years
      @ Abhay Koradiya: Actually I dont have even Activity. The Activity is an example of how it should work. I only have a NfcforflutterPlugin. Ok, I will edit the line On Android side to I have example Actitivy.