在 flutter 插件中捕获 onNewIntent() class

Catch onNewIntent() in flutter plugin class

问题标题可能有点混乱。我会尝试解释更多细节。

我正在写一个 flutter 插件来使用 NFC。

我有一个示例 Android Activity 在收到 NDEF 消息时触发 onNewIntent()。此时消息负载已准备好使用。

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
    }

我需要在插件中具有相同的功能 class。

这是我的插件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?) {
  }

由于 NfcforflutterPlugin 不是 Activity,我需要 NfcforflutterPlugin class 中的触发事件,因为 onNewIntent() 中 Android Activity 将在消息发现时刻调用,这样我就可以 运行 mEventSink.success(ndefMessage) 并将消息传递给 Flutter 端。

有什么想法吗?

实施 PluginRegistry.NewIntentListener 用于收听意图方法。检查 here.

它有onNewIntent方法。你可以使用它。喜欢,

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

建议大家参考或fork https://github.com/akeblom/flutter-nfc-reader

这个 repo 修复了 pub.dev https://pub.dev/packages/flutter_nfc_reader
中 flutter-nfc-reader 的一些问题 并且我用真机测试过,效果很好。

代码片段

class FlutterNfcReaderPlugin(val registrar: Registrar) : MethodCallHandler, EventChannel.StreamHandler, NfcAdapter.ReaderCallback {
...
init {
        nfcManager = activity.getSystemService(Context.NFC_SERVICE) as? NfcManager
        nfcAdapter = nfcManager?.defaultAdapter
    }    

第 112 行的事件通道处理

// EventChannel.StreamHandler methods
    override fun onListen(arguments: Any?, eventSink: EventChannel.EventSink?) {
      this.eventSink = eventSink
    }

完整代码https://github.com/akeblom/flutter-nfc-reader/blob/master/android/src/main/kotlin/it/matteocrippa/flutternfcreader/FlutterNfcReaderPlugin.kt

好的,我找到了最适合我的方法。

不需要 onNewIntent()。

正如@chunhunghan提到的,我实现了NfcAdapter.ReaderCallback。但是为了捕获触发事件,我使用 onTagDiscovered(tag: Tag)

看起来像:

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
  }
}