Android读取NFC卡片数据

这里以nfc公交卡为例子

使用如下
  1. 请将需要获取nfc数据的 Activity 对应的清单文件里面设置成 栈顶模式,并在intent 标签内添加 action -- nfc
java 复制代码
android:launchMode="singleTop"
java 复制代码
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
  1. 在对应Activity内的各个生命周期内加入以下代码
onCreate 创建nfc

初始化NFC show 里面是说明当前设备是否支持NFC是否打开NFC

java 复制代码
NfcUtil.createNfc(this,object : NfcUtil.NFCCreateBack{
            override fun show(s: String) {
                Log.e("NFC_TAG", "createNfc: -${s}", )
            }
        })

该设备是否支持NFC

java 复制代码
NfcUtil.getNFC(this)

跳到手机系统NFC设置界面

java 复制代码
NfcUtil.jumpNFC()
onResume 开启nfc监听
java 复制代码
NfcUtil.resumeNfc()
onPause 关闭nfc监听
java 复制代码
NfcUtil.pauseNfc()
onNewIntent 获取监听到的数据
java 复制代码
//这里必须setIntent,set  NFC事件响应后的intent才能拿到数据
        setIntent(intent)
        NfcUtil.resolveIntent(intent!!,object: NfcUtil.NFCBack{
            override fun onSuc(s: NfcUtil.NFCBean) {
                tv1?.text = "名称: ${s.tagID_hex}"
                tv2?.text = "ID: ${s.tagID_dec}"
                tv3?.text = "内存大小: ${s.tagID_size}"
                tv4?.text = "名称: ${s.msg}"
            }

        })

NfcUtil

java 复制代码
/**
 * Nfc读取工具类
 * */
@SuppressLint("StaticFieldLeak")
object NfcUtil {

    private var activity: Activity? = null
    var mNfcAdapter: NfcAdapter? = null
    var pIntent: PendingIntent? = null
    lateinit var mIntentFilter: Array<IntentFilter>
    lateinit var mTechList: Array<Array<String>>

    //创建必要数据
    fun createNfc(a: Activity,c: NFCCreateBack){
        activity = a
        mNfcAdapter = NfcAdapter.getDefaultAdapter(activity)
        if (mNfcAdapter == null) {
            c.show("设备不支持NFC!")
        }else{
            if (!mNfcAdapter!!.isEnabled) {
                c.show("请在系统设置中先启用NFC功能!")
            }
            pIntent = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
                PendingIntent.getActivity(activity, 0, Intent(activity,activity?.javaClass).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), PendingIntent.FLAG_MUTABLE )
            } else {
                PendingIntent.getActivity(activity, 0, Intent(activity, activity?.javaClass).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0)
            }
        }
    }

    //创建回调
    interface NFCCreateBack{
        fun show(s: String)
    }


    //进入界面调用
    fun resumeNfc(){
        mNfcAdapter?.let {
            //intentFilter过滤----ndef
            val ndefFilter = IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED)
            try {
                //文本类型
                ndefFilter.addDataType("text/plain")
            } catch (e: MalformedMimeTypeException) {
                e.printStackTrace()
            }
            //intentFilter过滤----非ndef
            val techFilter = IntentFilter(NfcAdapter.ACTION_TECH_DISCOVERED)
            val tag = IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED)

            //intentFilter过滤器列表
            mIntentFilter = arrayOf(ndefFilter,techFilter,tag)
            //匹配的数据格式列表
            mTechList = arrayOf(
                arrayOf(MifareClassic::class.java.name),
                arrayOf(NfcA::class.java.name),
                arrayOf(Ndef::class.java.name),
                arrayOf(NdefFormatable::class.java.name)
            )
            it.enableForegroundDispatch(activity, pIntent, mIntentFilter, mTechList)
        }
    }

    //去除NFC监听
    fun pauseNfc(){
        mNfcAdapter?.disableForegroundDispatch(activity)
    }

    //处理接收到的NFC数据
    fun resolveIntent(intent: Intent,nfcBack: NFCBack){
        val action = intent.action
        Log.e("NFC_TAG", "action Type: $action")
       if (NfcAdapter.ACTION_TECH_DISCOVERED == intent.action) {
            val tag1: Parcelable? = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG)
            if (tag1 != null) {
                Log.e("NFC_TAG", "解析数据: ${dumpTagData66(tag1,nfcBack)}")
                dumpTagData66(tag1,nfcBack)
            }
        }else {
           val tag: Tag? = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG)
           var tagIDHex: String = ""
           var tagIDDec: String = ""
           val tagIDSize: String = "1024"
           if (tag != null) {
               val nfcId = dumpTagData(tag)
               tagIDHex = getHex(tag.id).toString()
               tagIDDec = getDec(tag.id).toString()
               if (nfcId.isNotEmpty()) {
                   Log.e("NFC_TAG", "接收到卡片ID: $nfcId")
               } else {
                   Log.e("NFC_TAG", "识别失败!请重新刷卡!")
               }

           }
           nfcBack.onSuc(NFCBean(tagIDHex,tagIDDec,tagIDSize,""))
       }
    }

    //回调
    interface NFCBack{
        fun onSuc(s: NFCBean)
    }

    //数据内容实体类
    data class NFCBean(
        var tagID_hex: String? = "", //id,不同的解析
        var tagID_dec: String? = "", //id,不同的解析
        var tagID_size: String? = "", //id,不同的解析
        var msg: String? = "" //详细数据
    )

    private fun dumpTagData(p: Tag): String {
        val id = p.id
        return bytesToHexString(id)
    }

    /**
     * 将字节数组转换为字符串
     */
    private fun bytesToHexString(inT: ByteArray): String {
        var i: Int
        var iny: Int
        val hex =
            arrayOf("0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F")
        var out = ""
        var j: Int = 0
        while (j < inT.size) {
            iny = inT[j].toInt() and 0xff
            i = iny shr 4 and 0x0f
            out += hex[i]
            i = iny and 0x0f
            out += hex[i]
            ++j
        }
        return out
    }

    //一般公家卡,扫描的信息
    private fun dumpTagData66(p: Parcelable,nfcBack: NFCBack): String {

        var tagIDHex: String = ""
        var tagIDDec: String = ""
        var tagIDSize: String = "1024"
        var msg = ""

        val sb = java.lang.StringBuilder()
        val tag = p as Tag
        val id = tag.id
        sb.append("Tag ID (hex): ").append(getHex(id)).append("\n")
        sb.append("Tag ID (dec): ").append(getDec(id)).append("\n")
        sb.append("ID (reversed): ").append(getReversed(id)).append("\n")
        val prefix = "android.nfc.tech."
        sb.append("Technologies: ")

        tagIDHex = getHex(id).toString()
        tagIDDec = getDec(id).toString()
        for (tech in tag.techList) {
            sb.append(tech.substring(prefix.length))
            sb.append(", ")
        }
        sb.delete(sb.length - 2, sb.length)
        for (tech in tag.techList) {
            if (tech == MifareClassic::class.java.name) {
                sb.append('\n')
                val mifareTag = MifareClassic.get(tag)
                tagIDSize = mifareTag.size.toString()
                var type = "Unknown"
                when (mifareTag.type) {
                    MifareClassic.TYPE_CLASSIC -> type = "Classic"
                    MifareClassic.TYPE_PLUS -> type = "Plus"
                    MifareClassic.TYPE_PRO -> type = "Pro"
                }
                sb.append("Mifare Classic type: ")
                sb.append(type)
                sb.append('\n')
                sb.append("Mifare size: ")
                sb.append("${mifareTag.size} bytes")
                sb.append('\n')
                sb.append("Mifare sectors: ")
                sb.append(mifareTag.sectorCount)
                sb.append('\n')
                sb.append("Mifare blocks: ")
                sb.append(mifareTag.blockCount)
            }
            if (tech == MifareUltralight::class.java.name) {
                sb.append('\n')
                val mifareUlTag: MifareUltralight = MifareUltralight.get(tag)
                var type = "Unknown"
                when (mifareUlTag.type) {
                    MifareUltralight.TYPE_ULTRALIGHT -> type = "Ultralight"
                    MifareUltralight.TYPE_ULTRALIGHT_C -> type = "Ultralight C"
                }
                sb.append("Mifare Ultralight type: ")
                sb.append(type)
            }
        }
        msg = sb.toString()
        nfcBack.onSuc(NFCBean(tagIDHex,tagIDDec,tagIDSize,msg))
        return sb.toString()
    }

    private fun getHex(bytes: ByteArray): String? {
        val sb = StringBuilder()
        for (i in bytes.indices.reversed()) {
            val b = bytes[i].toInt() and 0xff
            if (b < 0x10) sb.append('0')
            sb.append(Integer.toHexString(b))
            if (i > 0) {
                sb.append(" ")
            }
        }
        return sb.toString()
    }

    private fun getDec(bytes: ByteArray): Long {
        var result: Long = 0
        var factor: Long = 1
        for (i in bytes.indices) {
            val value = bytes[i].toLong() and 0xffL
            result += value * factor
            factor *= 256L
        }
        return result
    }

    private fun getReversed(bytes: ByteArray): Long {
        var result: Long = 0
        var factor: Long = 1
        for (i in bytes.indices.reversed()) {
            val value = bytes[i].toLong() and 0xffL
            result += value * factor
            factor *= 256L
        }
        return result
    }

    /**
     * 跳转到NFC设置界面*/
    fun jumpNFC(){
        val setNfc = Intent(Settings.ACTION_NFC_SETTINGS)
        activity!!.startActivity(setNfc)
    }

    /**
     * 该设备是否支持NFC*/
    fun getNFC(context: Context): Boolean{
        val packageManager = context.packageManager
        return packageManager.hasSystemFeature(PackageManager.FEATURE_NFC)
    }
}
相关推荐
拭心3 小时前
Google 提供的 Android 端上大模型组件:MediaPipe LLM 介绍
android
带电的小王6 小时前
WhisperKit: Android 端测试 Whisper -- Android手机(Qualcomm GPU)部署音频大模型
android·智能手机·whisper·qualcomm
梦想平凡6 小时前
PHP 微信棋牌开发全解析:高级教程
android·数据库·oracle
元争栈道6 小时前
webview和H5来实现的android短视频(短剧)音视频播放依赖控件
android·音视频
阿甘知识库7 小时前
宝塔面板跨服务器数据同步教程:双机备份零停机
android·运维·服务器·备份·同步·宝塔面板·建站
元争栈道8 小时前
webview+H5来实现的android短视频(短剧)音视频播放依赖控件资源
android·音视频
MuYe8 小时前
Android Hook - 动态加载so库
android
居居飒9 小时前
Android学习(四)-Kotlin编程语言-for循环
android·学习·kotlin
Henry_He12 小时前
桌面列表小部件不能点击的问题分析
android
工程师老罗12 小时前
Android笔试面试题AI答之Android基础(1)
android