Android WebView应用集成NFC读取功能技术求助
给WebView应用添加NFC扫描启动并跳转自定义网页的完整指南
嘿,作为新手完全不用慌!咱们一步步拆解,把NFC集成的事儿给你捋得明明白白:
第一步:更新Android Manifest文件
首先得给应用声明NFC相关的权限和能力,让系统知道你的应用能处理NFC标签。把你现有的Manifest补全成这样:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="web.webapp"> <!-- 声明NFC权限 --> <uses-permission android:name="android.permission.NFC" /> <!-- 告诉系统应用依赖NFC功能,无NFC的设备会自动过滤该应用 --> <uses-feature android:name="android.hardware.nfc" android:required="true" /> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> <!-- 添加NFC标签触发的Intent Filter,实现未打开应用时扫描启动 --> <intent-filter> <action android:name="android.nfc.action.NDEF_DISCOVERED" /> <category android:name="android.intent.category.DEFAULT" /> <!-- 匹配文本类型标签,若你的标签是URL则改用text/uri-list --> <data android:mimeType="text/plain" /> </intent-filter> <!-- 兼容未格式化的NDEF标签 --> <intent-filter> <action android:name="android.nfc.action.TECH_DISCOVERED" /> </intent-filter> <meta-data android:name="android.nfc.action.TECH_DISCOVERED" android:resource="@xml/nfc_tech_filter" /> </activity> </application> </manifest>
接着在res/xml目录下新建nfc_tech_filter.xml(没有xml目录就手动创建),指定应用支持的NFC技术类型:
<?xml version="1.0" encoding="utf-8"?> <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>
第二步:修改WebView主Activity
在你的MainActivity里添加NFC处理逻辑,核心是捕获标签数据,再让WebView加载带参数的自定义网页。假设你的主Activity原本就是加载WebView的,修改后代码如下:
import android.nfc.NdefMessage; import android.nfc.NdefRecord; import android.nfc.NfcAdapter; import android.nfc.Tag; import android.nfc.tech.Ndef; import android.os.Bundle; import android.widget.Toast; import androidx.appcompat.app.AppCompatActivity; import java.io.UnsupportedEncodingException; import java.nio.charset.StandardCharsets; import android.content.Intent; import android.webkit.WebView; import android.webkit.WebViewClient; public class MainActivity extends AppCompatActivity { private NfcAdapter nfcAdapter; private WebView webView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 初始化WebView基础配置 webView = findViewById(R.id.webview); webView.setWebViewClient(new WebViewClient()); webView.getSettings().setJavaScriptEnabled(true); // 初始化NFC适配器 nfcAdapter = NfcAdapter.getDefaultAdapter(this); // 检查设备NFC支持情况 if (nfcAdapter == null) { Toast.makeText(this, "你的设备不支持NFC功能", Toast.LENGTH_LONG).show(); return; } // 检查NFC是否开启 if (!nfcAdapter.isEnabled()) { Toast.makeText(this, "请先开启NFC功能", Toast.LENGTH_LONG).show(); } // 处理扫描NFC启动应用的Intent handleNfcIntent(getIntent()); } @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); // 应用已打开时,扫描NFC触发此方法处理标签数据 handleNfcIntent(intent); } private void handleNfcIntent(Intent intent) { String action = intent.getAction(); // 判断是否为NFC相关意图 if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(action) || NfcAdapter.ACTION_TECH_DISCOVERED.equals(action)) { Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); String tagContent = readNdefTag(tag); if (tagContent != null && !tagContent.isEmpty()) { // 拼接自定义网页链接,将标签内容作为参数传递 String customUrl = "https://你的自定义域名.com/nfc页面?data=" + tagContent; // 让WebView加载目标网页 webView.loadUrl(customUrl); } else { Toast.makeText(this, "无法读取NFC标签内容", Toast.LENGTH_SHORT).show(); } } } // 读取NDEF格式标签内容 private String readNdefTag(Tag tag) { Ndef ndef = Ndef.get(tag); if (ndef == null) { // 非NDEF格式标签,可在此扩展其他格式处理逻辑(如MifareClassic) return null; } NdefMessage ndefMessage = ndef.getCachedNdefMessage(); if (ndefMessage == null) { return null; } NdefRecord[] records = ndefMessage.getRecords(); for (NdefRecord record : records) { // 处理文本类型记录 if (record.getTnf() == NdefRecord.TNF_WELL_KNOWN && new String(record.getType()).equals(NdefRecord.RTD_TEXT)) { try { return parseTextRecord(record); } catch (UnsupportedEncodingException e) { e.printStackTrace(); return null; } } // 处理URL类型记录 else if (record.getTnf() == NdefRecord.TNF_WELL_KNOWN && new String(record.getType()).equals(NdefRecord.RTD_URI)) { return parseUriRecord(record); } } return null; } // 解析文本类型NDEF记录 private String parseTextRecord(NdefRecord record) throws UnsupportedEncodingException { byte[] payload = record.getPayload(); // 第一个字节包含编码信息 String encoding = ((payload[0] & 0x80) == 0) ? StandardCharsets.UTF_8.name() : StandardCharsets.UTF_16.name(); // 提取语言代码长度 int languageCodeLength = payload[0] & 0x3F; // 提取真实文本内容 return new String(payload, languageCodeLength + 1, payload.length - languageCodeLength - 1, encoding); } // 解析URL类型NDEF记录 private String parseUriRecord(NdefRecord record) { byte[] payload = record.getPayload(); // NFC规范定义的URL前缀映射 String[] uriPrefixes = new String[]{ "", "http://www.", "https://www.", "http://", "https://", "tel:", "mailto:", "ftp://anonymous:anonymous@", "ftp://ftp.", "ftps://", "sftp://", "smb://", "nfs://", "ftp://", "dav://", "news:", "telnet://", "imap:", "rtsp://", "urn:", "pop:", "sip:", "sips:", "tftp:", "btspp://", "btl2cap://", "btgoep://", "tcpobex://", "irdaobex://", "file://", "urn:epc:id:", "urn:epc:tag:", "urn:epc:pat:", "urn:epc:raw:", "urn:epc:", "urn:nfc:" }; int prefixIndex = payload[0] & 0xFF; String prefix = uriPrefixes[prefixIndex]; byte[] uriBytes = new byte[payload.length - 1]; System.arraycopy(payload, 1, uriBytes, 0, uriBytes.length); return prefix + new String(uriBytes, StandardCharsets.UTF_8); } }
第三步:测试验证
- 确保测试设备支持NFC并已开启该功能
- 用NFC写入工具给标签写入文本或URL内容
- 关闭应用后扫描标签,验证应用是否自动启动并跳转至带参数的自定义网页
- 打开应用后扫描标签,验证WebView是否能正常跳转
新手注意事项
- 大部分商用NFC标签都是NDEF格式,若你用的是非NDEF标签,需要额外扩展处理逻辑
- 记得把代码中的
https://你的自定义域名.com/nfc页面?data=替换为你实际的网页地址 - 若测试失败,优先检查Manifest的权限、Intent Filter配置,以及标签内容是否匹配代码处理的类型
内容的提问来源于stack exchange,提问作者Matt Penfold
相关产品推荐
相关产品推荐

