如何将 uid NFC 与 csv 数据库进行比较(标签:Mifare DESFire:ISO14443-4:A 型,Isodep)

问题描述 投票:0回答:1

我的应用程序启动了,但当我放置 NFC 标签时什么也没发生。 目标通常很简单,放置 nfc 标签,将 uid 与 csv 数据库进行比较。

Mifare DESFire:ISO14443-4:A 型,Isodep 标签包含安全证书,因为该卡在公司中使用,唯一开放的东西是 UID。

mainactivity.kt:

package com.example.simplicims

import android.nfc.NfcAdapter
import android.Manifest
import android.app.Activity
import android.content.Intent
import android.content.pm.PackageManager
import android.nfc.Tag
import android.nfc.tech.NfcA
import android.os.Bundle
import android.util.Log
import android.widget.Button
import android.widget.TextView
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import java.io.BufferedReader
import java.io.File
import java.io.FileInputStream
import java.io.FileReader
import java.io.IOException
import java.io.InputStream
import org.apache.poi.ss.usermodel.WorkbookFactory

class MainActivity : Activity() {

    private lateinit var nfcAdapter: NfcAdapter
    private lateinit var uidTextView: TextView
    private lateinit var statusTextView: TextView
    private lateinit var scanButton: Button

    private val validUids = mutableListOf<String>()  // List to store valid UIDs from CSV

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

        uidTextView = findViewById(R.id.uidTextView)
        statusTextView = findViewById(R.id.statusTextView)
        scanButton = findViewById(R.id.scanButton)

        nfcAdapter = NfcAdapter.getDefaultAdapter(this)

        // Check for permissions and load CSV file
        checkPermissions()

        scanButton.setOnClickListener {
            // Trigger NFC scan manually if needed
            // Optionally, start an activity for NFC scan manually
        }
    }

    override fun onResume() {
        super.onResume()
        val nfcAdapter = NfcAdapter.getDefaultAdapter(this)

        if (NfcAdapter.getDefaultAdapter(this) == null) {
            statusTextView.text = "NFC non dispo"
            return
        } else {
            if (nfcAdapter.isEnabled) {
                Log.e("NFC", "NFC is disabled")
            } else {
                nfcAdapter.enableForegroundDispatch(this, null, null, null)
            }
        }
    }

    override fun onPause() {
        super.onPause()
        nfcAdapter.disableForegroundDispatch(this)
    }

    override fun onNewIntent(intent: Intent?) {
        super.onNewIntent(intent)
        if (NfcAdapter.ACTION_NDEF_DISCOVERED == intent?.action) {
            val tag: Tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG)!!
            val uid = tag.id.joinToString("") { it.toString(16).padStart(2, '0') }
            uidTextView.text = "UID: $uid"
            checkUidInDatabase(uid)
        }
    }

    private fun loadCsvDatabase() {
        try {
            val csvFile = File("/storage/emulated/0/Download/database.csv") // CSV file path
            if (!csvFile.exists()) {
                statusTextView.text = "CSV file not found"
                return
            }

            val reader = BufferedReader(FileReader(csvFile))
            var line: String?

            while (reader.readLine().also { line = it } != null) {
                // Assuming each line contains a single UID
                val uid = line?.trim() // Remove any unnecessary whitespace
                if (!uid.isNullOrEmpty()) {
                    validUids.add(uid)
                }
            }
            reader.close()

        } catch (e: IOException) {
            statusTextView.text = "Error reading CSV file"
        }
    }

    private fun checkUidInDatabase(uid: String) {
        if (validUids.contains(uid)) {
            statusTextView.text = "Entrée autorisée"
            statusTextView.setTextColor(getColor(android.R.color.holo_green_dark))
        } else {
            statusTextView.text = "Entrée non autorisée - voir CSB"
            statusTextView.setTextColor(getColor(android.R.color.holo_red_dark))
        }
    }

    // Check for permission to read external storage
    private fun checkPermissions() {
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE), 1)
        } else {
            // If permission is granted, load the CSV
            loadCsvDatabase()
        }
    }

    // Handle the result of permission request
    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        if (requestCode == 1) {
            if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // Permission granted, load the CSV
                loadCsvDatabase()
            } else {
                // Permission denied, handle accordingly
                statusTextView.text = "Permission denied to read external storage"
            }
        }
    }
}

清单:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.example.simplicims">
    <uses-permission android:name="android.permission.NFC" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-feature android:name="android.hardware.nfc" android:required="true" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="simpliCIMS"
        android:theme="@style/Theme.SimpliCIMS">

        <activity
            android:name=".MainActivity"
            android:label="simpliCIMS"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>

            <meta-data
                android:name="android.nfc.action.NDEF_DISCOVERED"
                android:value="text/plain" />
        </activity>
    </application>
</manifest>

我只想放置一个 NFC 标签,并根据 UID 是否在数据库中获得 OK 或 NOK。 仅此而已,但我每次都失败了。 我使用人工智能是因为我不是开发人员,即使我试图理解一些事情。

android csv nfc uid
1个回答
0
投票

警告:尝试仅使用 NFC UID 来授权访问,就像您所做的那样,是非常不安全的。不保证 NFC UID 是唯一的。有很容易获得的硬件可以复制它们并相当快速地暴力破解它们。

也就是说,主要问题之一是您的代码没有寻找正确类型的 NFC 标签,或者实际上根本没有寻找任何类型的 NFC 标签。

您的程序可以使用多种方法来告诉 Android NFC 服务,当它看到特定类型的 NFC 标签时,应将其发送到您的应用程序。取决于您的应用程序是否已在运行以及它运行的启动模式以及安装了哪些其他 NFC 应用程序。

您已使用 NFC Manifest Intent 过滤器指示 Android NFC 服务在发现带有 NDEF 数据记录的标签时将有关标签的数据发送到您的应用程序。

问题是您的标签上没有 NDEF 数据记录,因此您的应用程序永远不会收到您的 ISO14443-4 :A 型、Isodep 已提交的通知。

然后您已使用

enableForegroundDispatch
告诉 Android NFC 服务您不想收到有关任何 NFC 标签的通知,因为您已传递了所有
null
参数。

更正常的做法是,当出现某种类型的 NFC 标签(如果尚未运行)时,使用清单意图过滤器启动您的应用程序,然后使用 2 个前台系统之一,在出现正确类型的标签时专门收到通知(这两个前台系统是

enableForegroundDispatch
或更好、更新的
enableReaderMode
)

因此,要首先解决此问题,您需要为您的标签类型使用正确的清单意图过滤器

在名为

<project-root>/res/xml
nfc_tech_filter.xml

文件夹中创建 XML 文件资源

在此文件中创建一个与您的标签详细信息相匹配的技术列表,例如“NFC Type A”和“NFC IsoDep”

<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
    <tech-list>
        <tech>android.nfc.tech.NfcA</tech>
        <tech>android.nfc.tech.IsoDep</tech>
    </tech-list>
</resources>

编辑清单以使用此 XML 文件。例如更改您的活动的元数据元素。

<meta-data android:name="android.nfc.action.TECH_DISCOVERED"
    android:resource="@xml/nfc_tech_filter" />

您还需要更改处理意图的方式

override fun onNewIntent(intent: Intent?) {
  super.onNewIntent(intent)
  processIntent(intent)
}

fun processIntent(intent: Intent?) {
  if (NfcAdapter.ACTION_TECH_DISCOVERED == intent?.action) {
    val tag: Tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG)!!
    val uid = tag.id.joinToString("") { it.toString(16).padStart(2, '0') }
    uidTextView.text = "UID: $uid"
    checkUidInDatabase(uid)
  }
}

// Then add to `onCreate` method 
//because the Intent might be delivered to onCreate instead of onNewIntent
processIntent(getIntent())


这一切都在 Android NFC 文档

要使

enableForegroundDispatch
工作,您需要为其提供一个待定意图,以便它将标签数据传回给您。

val intent = Intent(this, javaClass).apply {
    addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)
}
var pendingIntent: PendingIntent = PendingIntent.getActivity(this, 0, intent,
        PendingIntent.FLAG_MUTABLE)
adapter.enableForegroundDispatch(this, pendingIntent, null, null)
// Should really set the nulls to a be a Tech filter for NfcA and IsoDep
// But this will match ALL Tags

也在 Android 文档

希望这能与您的标签相匹配(并且是正确的,因为我通常使用更新更好的

enableReaderMode
,而不是在 Kotlin 中)

© www.soinside.com 2019 - 2024. All rights reserved.