You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过NFC向电子纸NFC模块传输图片?Kotlin开发求助

问题分析与解决方案

核心误区:混淆Android Beam与NFC标签读写

你使用的setNdefPushMessage和setBeamPushUris是Android Beam对等传输API,仅用于两个支持Beam的Android设备间传输数据。而你对接的Good Display电子纸NFC模块,大概率是被动式NFC标签(仅存储数据,由主动设备读写),因此这两种方法完全不适用,这是失败的核心原因。


正确实现步骤:NFC标签写入NDEF数据

1. 配置权限与Manifest

在AndroidManifest.xml中添加NFC权限及相关配置:

<uses-permission android:name="android.permission.NFC" />
<uses-feature android:name="android.hardware.nfc" android:required="true" />

<activity ...>
    <!-- 过滤NFC标签发现的Intent -->
    <intent-filter>
        <action android:name="android.nfc.action.TAG_DISCOVERED" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
    <intent-filter>
        <action android:name="android.nfc.action.NDEF_DISCOVERED" />
        <data android:mimeType="image/jpeg" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
    <intent-filter>
        <action android:name="android.nfc.action.TECH_DISCOVERED" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
    <!-- 指定支持的NFC技术类型 -->
    <meta-data
        android:name="android.nfc.action.TECH_DISCOVERED"
        android:resource="@xml/nfc_tech_filter" />
</activity>

创建res/xml/nfc_tech_filter.xml定义支持的标签技术:

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

2. 实现标签检测与写入逻辑

替换原有点击事件,改为监听NFC标签发现事件并写入图片数据:

private var nfcAdapter: NfcAdapter? = null
private var pendingIntent: PendingIntent? = null

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    
    nfcAdapter = NfcAdapter.getDefaultAdapter(this)
    pendingIntent = PendingIntent.getActivity(
        this, 0,
        Intent(this, javaClass).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP),
        PendingIntent.FLAG_MUTABLE
    )

    sendButton = findViewById(R.id.btn_sendImage)
    sendButton.setOnClickListener {
        if (nfcAdapter?.isEnabled == false) {
            openNfcSettings()
        } else {
            Toast.makeText(this, "请将手机靠近NFC模块", Toast.LENGTH_SHORT).show()
        }
    }
}

override fun onResume() {
    super.onResume()
    nfcAdapter?.enableForegroundDispatch(this, pendingIntent, null, null)
}

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

override fun onNewIntent(intent: Intent?) {
    super.onNewIntent(intent)
    intent?.let { handleNfcIntent(it) }
}

private fun handleNfcIntent(intent: Intent) {
    val tag = intent.getParcelableExtra<Tag>(NfcAdapter.EXTRA_TAG) ?: return
    val imageByteArray = // 替换为你的图片ByteArray(需压缩到标签容量范围内)
    val ndefMessage = createNdefMessage(imageByteArray)
    
    // 尝试写入NDEF数据
    try {
        val ndef = Ndef.get(tag)
        if (ndef != null) {
            ndef.connect()
            if (!ndef.isWritable) {
                Toast.makeText(this, "标签不可写", Toast.LENGTH_SHORT).show()
                ndef.close()
                return
            }
            if (ndef.maxSize < ndefMessage.toByteArray().size) {
                Toast.makeText(this, "图片过大,超过标签容量", Toast.LENGTH_SHORT).show()
                ndef.close()
                return
            }
            ndef.writeNdefMessage(ndefMessage)
            Toast.makeText(this, "写入成功", Toast.LENGTH_SHORT).show()
            ndef.close()
        } else {
            // 标签未格式化,尝试格式化并写入
            val ndefFormatable = NdefFormatable.get(tag)
            ndefFormatable?.let {
                it.connect()
                it.format(ndefMessage)
                Toast.makeText(this, "格式化并写入成功", Toast.LENGTH_SHORT).show()
                it.close()
            } ?: run {
                Toast.makeText(this, "不支持NDEF格式的标签", Toast.LENGTH_SHORT).show()
            }
        }
    } catch (e: Exception) {
        Toast.makeText(this, "写入失败:${e.message}", Toast.LENGTH_SHORT).show()
    }
}

private fun createNdefMessage(image: ByteArray): NdefMessage {
    val mimeRecord = NdefRecord.createMime("image/jpeg", image)
    return NdefMessage(mimeRecord)
}

private fun openNfcSettings() {
    startActivity(Intent(Settings.ACTION_NFC_SETTINGS))
}

关键注意事项

  • 图片大小限制:NFC标签容量通常极小(如NTAG213仅144字节,NTAG216为888字节),需将图片压缩到极小尺寸(比如128x128像素以下的JPEG),否则会超出容量。
  • 标签兼容性:确认你的NFC模块支持NDEF格式,若仅支持原始数据写入,需使用NfcA/NfcB等原始技术类发送APDU指令,需参考模块官方文档获取通信协议。
  • 版本适配:Android 12+需使用PendingIntent.FLAG_MUTABLE,注意权限与Intent配置的兼容性。

内容的提问来源于stack exchange,提问作者SatanasHammer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 16:25:30