Android端Chrome使用NDEFReader API操作NFC标签触发原生服务问题求助
NDEFReader读写NFC标签时被Android原生NFC服务拦截 我尝试用Chrome的NDEFReader对可写NFC标签执行读写操作,已遵循官方文档步骤实现功能。通过HTTPS部署网页后,在Android 10(版本QKQ1.190825.002)设备的Chrome 113.0.5672.131版本中,授予NFC权限后,扫描或写入标签时,网页未处理记录,反而跳转至Android原生NFC服务应用显示内容。
请问是否可让Chrome保持前台处理,避免原生NFC服务介入?以下是测试代码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <title>test</title> <base href="/" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> </head> <body> <div id="output"></div> <button id="scanButton" style="padding: 20px; font-size:20px; display: none;">SCAN</button> <div> <input type="text" id="text"> <button id="write" style="padding: 20px; font-size:20px;">WRITE</button> </div> </body> <script> const ndef = new NDEFReader(); const outputDiv = document.querySelector('#output'); const writeBtn = document.querySelector('#write'); const nfcPermissionStatus = await navigator.permissions.query({ name: 'nfc' }); if (nfcPermissionStatus.state === 'granted') { await read(); } else { document.querySelector('#scanButton').style.display = 'block'; document.querySelector('#scanButton').onclick = async() => { await read(); }; } async function read() { await ndef.scan(); ndef.onreadingerror = () => { outputDiv.textContent = 'Cannot read data from the NFC tag. Try another one?'; }; ndef.onreading = ({ message }) => { for (const record of message.records) { switch (record.recordType) { case 'text': const textDecoder = new TextDecoder(record.encoding); outputDiv.innerHTML += `Text: ${textDecoder.decode(record.data)}<br>`; break; // currently, I am only interested in parsing text records // the rest of the cases are omitted } } }; } writeBtn.onclick = async() => { await ndef.scan(); try { const textInput = document.querySelector('#text'); await ndef.write({ records: [{ recordType: 'text', data: textInput.value }] }, { ignoreRead: true }); outputDiv.textContent = `Wrote text: ${textInput.value}`; } catch(err) { outputDiv.textContent = `Error: ${err}`; } } </script> </html>
解决方案
修改
scan()调用参数,启用后台处理权限
默认scan()的userVisibleOnly参数为true,系统会优先让可见应用(包括原生NFC服务)处理标签。添加userVisibleOnly: false可让Web NFC独占处理,同时配合AbortController控制扫描生命周期:async function read() { const abortController = new AbortController(); await ndef.scan({ signal: abortController.signal, userVisibleOnly: false }); ndef.onreadingerror = () => { outputDiv.textContent = 'Cannot read data from the NFC tag. Try another one?'; }; ndef.onreading = ({ message }) => { for (const record of message.records) { switch (record.recordType) { case 'text': const textDecoder = new TextDecoder(record.encoding); outputDiv.innerHTML += `Text: ${textDecoder.decode(record.data)}<br>`; break; } } }; }注意:该参数需要网页已获得持久化NFC权限,或在用户主动交互(如点击按钮)中调用,避免权限被拒绝。
移除写入流程中的冗余
scan()调用
你的写入函数中先调用了scan(),这会触发读取流程,可能与写入操作冲突。直接调用write()即可,write()本身会触发NFC探测:writeBtn.onclick = async() => { try { const textInput = document.querySelector('#text'); await ndef.write({ records: [{ recordType: 'text', data: textInput.value }] }, { ignoreRead: true }); outputDiv.textContent = `Wrote text: ${textInput.value}`; } catch(err) { outputDiv.textContent = `Error: ${err}`; } }设置Chrome为NFC默认处理应用
进入Android系统设置 -> NFC -> 默认应用,选择Chrome作为NFC标签的默认处理应用,系统会优先让Chrome处理NFC交互。使用空白或非系统识别类型的标签测试
如果标签包含系统默认会处理的记录(如URL、手机号),系统可能优先跳转。可先清空标签,或写入自定义文本记录后再测试。
内容的提问来源于stack exchange,提问作者ardentia

