0

我目前正在开发一个 Android NFC 应用程序。这个应用程序包含一个NavigationDrawer我可以访问 3 个不同的片段,每个片段对应于 3 个不同的 NFC 功能。

首先,我想验证我的应用程序是否可以扫描 NFC 标签(这里我有一个 NXP NTAG 5 boost 标签,它是一个 NFC Forum Type 5 标签)。

我的问题是,当我的应用程序运行时,onNewIntentmyMainActivity永远不会被调用。

我确定这不是由于硬件,因为我可以使用常见应用程序检测到这个标签,但这可能是由于我传递给NfcManager文件中的函数的参数,比如activity.applicationContext但我不确定。

现在,我指定我不希望在检测到标签时启动特定活动,我只想在应用程序运行时检测 NFC 标签。

你能帮助我吗?

MainActivity

class MainActivity : AppCompatActivity() {

    private lateinit var appBarConfiguration: AppBarConfiguration

    private val TAG = MainActivity::class.java.simpleName
    var tag: Tag? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        checkNFC(this)
        setupNFC(this)

        configureToolbar()

        val drawerLayout: DrawerLayout = findViewById(R.id.drawer_layout)
        val navView: NavigationView = findViewById(R.id.nav_view)
        val navController = findNavController(R.id.nav_host_fragment)
        // Passing each menu ID as a set of Ids because each
        // menu should be considered as top level destinations.
        appBarConfiguration = AppBarConfiguration(setOf(
                R.id.nav_memory, R.id.nav_tag, R.id.nav_product), drawerLayout)
        setupActionBarWithNavController(navController, appBarConfiguration)
        navView.setupWithNavController(navController)
    }

    override fun onCreateOptionsMenu(menu: Menu): Boolean {
        // Inflate the menu; this adds items to the action bar if it is present.
        menuInflater.inflate(R.menu.main, menu)
        return true
    }

    override fun onSupportNavigateUp(): Boolean {
        val navController = findNavController(R.id.nav_host_fragment)
        return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp()
    }

    private fun configureToolbar() {
        val toolbar: Toolbar = findViewById(R.id.toolbar)
        setSupportActionBar(toolbar)
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        if (requestCode == ENABLE_NFC_REQUEST_CODE) {
            onActivityResultOutSourced(this)
        } else {
            super.onActivityResult(requestCode, resultCode, data)
        }
    }

    override fun onResume() {
        super.onResume()
        onResumeOutSourced(this)
    }

    override fun onPause() {
        super.onPause()
        onPauseOutSourced(this)
    }

    override fun onNewIntent(intent: Intent) {
        super.onNewIntent(intent)
        tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG)
        Log.d(TAG, "Card ID: " + Tools.byteArrayToHex(tag!!.id))
        val techList = tag!!.techList

        //Check that the discovered tag is a vicinity tag
        if (techList[0] == "android.nfc.tech.NfcV") {
            val tagUid = tag!!.id
            nfcvTag = NfcV.get(tag)

            //ISO/IEC 15693 tags can be operated in two modes:
            // Select mode and Addressed mode.
            //To work in the select mode it is needed to send a SELECT
            // command at the beginning of communic.
            //In the address mode, the tag UID is sent within each command.
            //This application works in SELECT MODE.
            val select_command: ByteArray = RFCommands.cmd_select
            System.arraycopy(tagUid, 0, select_command, 2, 8)
            if (nfcvTag != null) {
                try {
                    nfcvTag!!.connect()
                    val select_respo = nfcvTag!!.transceive(select_command)
                    Log.d(TAG, "Select response: " +
                            Tools.byteArrayToHex(select_respo))
                } catch (e: IOException) {
                    e.printStackTrace()
                }
            }
        }
    }

    companion object {
        const val ENABLE_NFC_REQUEST_CODE = 0x11
        private var nfcvTag: NfcV? = null
    }
}

NfcManager:

    class NfcManager {
        companion object {
            private var mNfcAdapter: NfcAdapter? = null
            private var mPendingIntent: PendingIntent? = null
            private lateinit var writeTagFilters: Array<IntentFilter>
            private lateinit var mTechLists: Array<Array<String>>

        /**
         * Check the availability of NFC interface and let the user enable them
         * if not active during the activity creation
         */
        fun checkNFC(@NonNull activity: Activity) {
            if (activity.packageManager.hasSystemFeature(PackageManager.FEATURE_NFC)) {
                mNfcAdapter = NfcAdapter.getDefaultAdapter(activity.applicationContext)
                if (mNfcAdapter != null && !mNfcAdapter!!.isEnabled) {
                    AlertDialog.Builder(activity.applicationContext)
                            .setTitle(activity.resources.getString(R.string.dialog_nfc_not_enabled_title))
                            .setMessage(activity.resources.getString(R.string.dialog_nfc_not_enabled_msg))
                            .setPositiveButton(activity.resources.getString(R.string.dialog_nfc_not_enabled_positive_btn)
                            ) { _, _ -> activity.startActivityForResult(Intent(Settings.ACTION_NFC_SETTINGS), MainActivity.ENABLE_NFC_REQUEST_CODE) }
                            .setNegativeButton(activity.resources.getString(R.string.dialog_nfc_not_enabled_negative_btn)
                            ) { _, _ ->
                                Toast.makeText(activity.applicationContext, activity.resources.getString(R.string.nfc_not_enabled), Toast.LENGTH_LONG).show()
                                activity.finish()
                            }.show()
                }
            } else {
                Toast.makeText(activity.applicationContext, activity.resources.getString(R.string.nfc_not_enabled), Toast.LENGTH_LONG).show()
                activity.finish()
            }
        }

        /**
         * Create a generic PendingIntent that will be delivered to this activity.
         * The NFC stack will fill in the intent with the details of the discovered
         * tag before delivering it to this activity.
         */
        fun setupNFC(@NonNull activity: Activity) {
            mPendingIntent = PendingIntent.getActivity(activity, 0, Intent(
                    activity, javaClass)
                    .addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0)
            val tagDetected = IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED)
            writeTagFilters = arrayOf(tagDetected)
            mTechLists = arrayOf(arrayOf(
                    NfcV::class.java.name
            ))
        }

        fun onActivityResultOutSourced(@NonNull activity: Activity) {
            mNfcAdapter = NfcAdapter.getDefaultAdapter(activity)
            if (mNfcAdapter!!.isEnabled) {
                Toast.makeText(activity.applicationContext, activity.resources.getString(R.string.nfc_not_enabled), Toast.LENGTH_LONG).show()
                activity.finish()
            }
        }

        fun onResumeOutSourced(@NonNull activity: Activity) {
            if (mNfcAdapter != null) {
                mNfcAdapter!!.enableForegroundDispatch(activity, mPendingIntent, writeTagFilters, mTechLists)
            }
        }

        fun onPauseOutSourced(@NonNull activity: Activity) {
            if (mNfcAdapter != null) mNfcAdapter!!.disableForegroundDispatch(activity)
        }
    }
}

编辑:

“NfcManager”类的目标是尽可能多地封装 NFC 功能,以避免将它们放在“MainActivity”中。

问题是前面的代码不起作用,而下面的代码,其中包含在“MainActivity”中的逻辑运行良好。我真的不明白问题是什么。

MainActivity:

class MainActivity : AppCompatActivity() {

    private lateinit var appBarConfiguration: AppBarConfiguration

    private val TAG: String = this::class.java.simpleName
    private val ENABLE_NFC_REQUEST_CODE = 0x11
    private var mNfcAdapter: NfcAdapter? = null
    private var nfcvTag: NfcV? = null
    var tag: Tag? = null
    private var mPendingIntent: PendingIntent? = null
    private lateinit var writeTagFilters: Array<IntentFilter>
    private lateinit var mTechLists: Array<Array<String>>

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        checkNFC()
        mNfcAdapter = NfcAdapter.getDefaultAdapter(this)
        setNfcIntent()

        configureToolbar()

        val drawerLayout: DrawerLayout = findViewById(R.id.drawer_layout)
        val navView: NavigationView = findViewById(R.id.nav_view)
        val navController = findNavController(R.id.nav_host_fragment)
        // Passing each menu ID as a set of Ids because each
        // menu should be considered as top level destinations.
        appBarConfiguration = AppBarConfiguration(setOf(
                R.id.nav_memory, R.id.nav_tag, R.id.nav_product), drawerLayout)
        setupActionBarWithNavController(navController, appBarConfiguration)
        navView.setupWithNavController(navController)
    }

    override fun onCreateOptionsMenu(menu: Menu): Boolean {
        // Inflate the menu; this adds items to the action bar if it is present.
        menuInflater.inflate(R.menu.main, menu)
        return true
    }

    override fun onSupportNavigateUp(): Boolean {
        val navController = findNavController(R.id.nav_host_fragment)
        return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp()
    }

    private fun configureToolbar() {
        val toolbar: Toolbar = findViewById(R.id.toolbar)
        setSupportActionBar(toolbar)
    }

    private fun setNfcIntent() {
        // Create a generic PendingIntent that will be delivered to this activity. The NFC stack will fill
        // in the intent with the details of the discovered tag before delivering it to this activity.
        mPendingIntent = PendingIntent.getActivity(this, 0, Intent(
                applicationContext, javaClass)
                .addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0)
        val tagDetected = IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED)
        writeTagFilters = arrayOf(tagDetected)
        mTechLists = arrayOf(arrayOf(
                NfcV::class.java.name
        ))
    }

    override fun onActivityResult(requestCode: Int,
                                  resultCode: Int, data: Intent?) {
        if (requestCode == ENABLE_NFC_REQUEST_CODE) {
            mNfcAdapter = NfcAdapter.getDefaultAdapter(this)
            if (mNfcAdapter!!.isEnabled) {
                Toast.makeText(applicationContext, resources.getString(R.string.nfc_not_enabled), Toast.LENGTH_LONG).show()
                finish()
            }
        } else {
            super.onActivityResult(requestCode, resultCode, data)
        }
    }

    /**
     * Check the availability of NFC and BLE interfaces and let the user enable them
     * if not active during the activity creation
     */
    private fun checkNFC() {
        if (packageManager.hasSystemFeature(PackageManager.FEATURE_NFC)) {
            mNfcAdapter = NfcAdapter.getDefaultAdapter(this)
            if (mNfcAdapter != null && !mNfcAdapter!!.isEnabled) {
                AlertDialog.Builder(this)
                        .setTitle(resources.getString(R.string.dialog_nfc_not_enabled_title))
                        .setMessage(resources.getString(R.string.dialog_nfc_not_enabled_msg))
                        .setPositiveButton(resources.getString(R.string.dialog_nfc_not_enabled_positive_btn)
                        ) { dialog, which -> startActivityForResult(Intent(Settings.ACTION_NFC_SETTINGS), ENABLE_NFC_REQUEST_CODE) }
                        .setNegativeButton(resources.getString(R.string.dialog_nfc_not_enabled_negative_btn)
                        ) { dialog, which ->
                            Toast.makeText(applicationContext, resources.getString(R.string.nfc_not_enabled), Toast.LENGTH_LONG).show()
                            finish()
                        }.show()
            }
        } else {
            Toast.makeText(applicationContext, resources.getString(R.string.nfc_not_enabled), Toast.LENGTH_LONG).show()
            finish()
        }
    }

    override fun onResume() {
        super.onResume()
        if (mNfcAdapter != null) {
            mNfcAdapter!!.enableForegroundDispatch(this, mPendingIntent, writeTagFilters, mTechLists)
        }
    }

    override fun onPause() {
        super.onPause()
        if (mNfcAdapter != null) mNfcAdapter!!.disableForegroundDispatch(this)
    }

    override fun onNewIntent(intent: Intent) {
        super.onNewIntent(intent)
        tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG)
        Log.d(TAG, "Card ID: " + Tools.byteArrayToHex(tag!!.id))
        val techList = tag!!.techList

        //Check that the discovered tag is a vicinity tag
        if (techList[0] == "android.nfc.tech.NfcV") {
            val tagUid = tag!!.id
            nfcvTag = NfcV.get(tag)

            //ISO/IEC 15693 tags can be operated in two modes:
            // Select mode and Addressed mode.
            //To work in the select mode it is needed to send a SELECT
            // command at the beginning of communic.
            //In the address mode, the tag UID is sent within each command.
            //This application works in SELECT MODE.
            val select_command: ByteArray = RFCommands.cmd_select
            System.arraycopy(tagUid, 0, select_command, 2, 8)
            if (nfcvTag != null) {
                try {
                    nfcvTag!!.connect()
                    val select_respo: ByteArray = nfcvTag!!.transceive(select_command)
                    Log.d(TAG, "Select response: " +
                            Tools.byteArrayToHex(select_respo))
                } catch (e: IOException) {
                    e.printStackTrace()
                }
            }
        }
    }
}
4

0 回答 0