nfc
NFC 标签读取和 NDEF 写入。
NFC 标签读写:扫描 NDEF 记录、写入文本或 URI。需要支持 NFC 的 iPhone 硬件。
边界:仅读写 NDEF 格式标签;不含银行卡支付、门禁卡模拟。扫描/写入会弹出系统 NFC 会话,必须放在按钮回调里,不要在 body() 中自动触发。
#模块概览
| 项 | 说明 |
|---|---|
| 导入 | import nfc |
| 适合做什么 | 读取标签内容、写入链接/文本、物联网配对 |
| 调用时机 | scan() / write() 放在按钮回调 |
| 推荐顺序 | is_available() → scan() 或 write(records) |
| 记录格式 | type 为 text 或 uri,配合 payload 字符串 |
#快速开始
下面脚本检查 NFC 是否可用,并尝试扫描标签(需将手机靠近标签):
已复制
import nfc
if not nfc.is_available():
print("此设备不支持 NFC 读取")
else:
tag = nfc.scan(message="请将 iPhone 靠近 NFC 标签", timeout=30)
if tag:
for rec in tag.get("records", []):
print(rec.get("type"), rec.get("payload"))
else:
print("扫描失败或已取消")
写入一条文本记录:
已复制
import nfc
records = [{"type": "text", "payload": "Hello from PythonIDE"}]
ok = nfc.write(records, message="靠近标签以写入")
print("写入成功" if ok else "写入失败")
#AppUI 示例
扫描与写入分步放在按钮回调;界面只展示最近一次结果。
已复制
import appui
import nfc
state = appui.State(
available="—",
last_result="尚未操作",
detail="点击按钮开始",
)
def refresh_available():
state.available = "是" if nfc.is_available() else "否"
def scan_tag():
refresh_available()
if state.available != "是":
state.detail = "设备不支持 NFC"
return
tag = nfc.scan(message="请将 iPhone 靠近标签", timeout=30)
if not tag:
state.batch_update(last_result="扫描失败", detail="超时或用户取消")
return
records = tag.get("records", [])
lines = [f"{r.get('type')}: {r.get('payload')}" for r in records]
state.batch_update(
last_result=f"读到 {len(records)} 条记录",
detail="\n".join(lines) if lines else "空标签",
)
def write_demo():
refresh_available()
if state.available != "是":
state.detail = "设备不支持 NFC"
return
records = [{"type": "uri", "payload": "https://pythonide.xin"}]
ok = nfc.write(records, message="靠近标签以写入链接")
state.batch_update(
last_result="写入成功" if ok else "写入失败",
detail="https://pythonide.xin",
)
def body():
return appui.NavigationStack(
appui.Form([
appui.Section("NFC", [
appui.Button("扫描标签", action=scan_tag)
.button_style("bordered_prominent"),
appui.Button("写入示例链接", action=write_demo),
]),
appui.Section("状态", [
appui.LabeledContent("可用", value=state.available),
appui.LabeledContent("结果", value=state.last_result),
appui.Text(state.detail).foreground_color("secondaryLabel"),
]),
]).navigation_title("NFC")
)
appui.run(body, state=state)
#API 参考
#速查
| API | 作用 |
|---|---|
is_available() | 设备是否支持 NFC 读取 → bool |
scan(message, timeout=30) | 弹出扫描会话 → {"records": [...]} 或 None |
write(records, message) | 写入 NDEF 记录 → bool |
#可用性
is_available() — 检查硬件与系统是否支持 NFC 读取。
已复制
if nfc.is_available():
...
#扫描
scan(message="Hold your iPhone near an NFC tag", timeout=30.0) — 启动系统 NFC 扫描会话,阻塞直到完成、超时或取消。
返回 {"records": [{"type": "text"|"uri", "payload": "..."}, ...]},失败返回 None。
已复制
tag = nfc.scan(message="请将 iPhone 靠近标签", timeout=30)
#写入
write(records, message="Hold your iPhone near an NFC tag to write") — 将 NDEF 记录写入标签。
| 字段 | 说明 |
|---|---|
type | "text" 或 "uri" |
payload | 文本或 URL 字符串 |
已复制
nfc.write([
{"type": "text", "payload": "会议室 A"},
{"type": "uri", "payload": "https://example.com"},
])
#常见错误
| 错误写法 | 后果 | 修正 |
|---|---|---|
未检查 is_available() | 在不支持设备上崩溃 | 先判断可用性 |
在 body() 里调用 scan() | 每次刷新都弹 NFC 会话 | 放进按钮回调 |
records 缺少 type/payload | 写入失败 | 按 NDEF 格式构造列表 |
| 用 NFC 做支付/门禁模拟 | 超出模块能力 | 使用对应系统 App 或专用 SDK |
#相关文档
#预期效果
运行示例后,界面应出现文档描述的目标结果;若与预期不符,先看「失败路径」并按返回值或日志排查。