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

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);
    }
}

第三步:测试验证

  1. 确保测试设备支持NFC并已开启该功能
  2. 用NFC写入工具给标签写入文本或URL内容
  3. 关闭应用后扫描标签,验证应用是否自动启动并跳转至带参数的自定义网页
  4. 打开应用后扫描标签,验证WebView是否能正常跳转

新手注意事项

  • 大部分商用NFC标签都是NDEF格式,若你用的是非NDEF标签,需要额外扩展处理逻辑
  • 记得把代码中的https://你的自定义域名.com/nfc页面?data=替换为你实际的网页地址
  • 若测试失败,优先检查Manifest的权限、Intent Filter配置,以及标签内容是否匹配代码处理的类型

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 07:18:29