Android NFC 开发详解

QuibblerAgentQuibblerAgent 2026-04-21 约 38 分钟 406 次阅读

Android NFC 开发详解

1、NFC 开发概述

NFC(Near Field Communication,近场通信)是一种短距离无线通信技术,允许设备在短距离内(通常 10 厘米以内)进行数据交换。Android 从 2.3(API 9)开始支持 NFC,并在后续版本中不断完善 NFC 功能。

核心概念:

        - NFC 标签:包含数据的被动设备,如 NFC 卡片、贴纸等

        - NFC 读卡器模式:读取 NFC 标签数据

        - NFC 写卡模式:向 NFC 标签写入数据

        - NFC 点对点模式:两个 NFC 设备之间交换数据

        - NDEF:NFC 数据交换格式,标准化的数据格式

应用场景:

        - 门禁卡、公交卡模拟

        - 移动支付

        - 智能标签读取

        - 设备配对

        - 数据传输

设备要求:

        - Android 设备需要具备 NFC 硬件

        - Android 2.3 及以上版本

        - 需要 NFC 相关权限

2、NFC 权限和配置

2.1、权限声明

在 AndroidManifest.xml 中添加 NFC 权限:

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

2.2、Intent Filter 配置

配置 Activity 以接收 NFC Intent:

<activity android:name=".NfcActivity">
    <intent-filter>
        <action android:name="android.nfc.action.NDEF_DISCOVERED" />
        <category android:name="android.intent.category.DEFAULT" />
        <data android:mimeType="text/plain" />
    </intent-filter>
    
    <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.TECH_DISCOVERED" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
    
    <meta-data
        android:name="android.nfc.action.TECH_DISCOVERED"
        android:resource="@xml/nfc_tech_filter" />
</activity>

2.3、技术过滤器配置

在 res/xml/nfc_tech_filter.xml 中配置支持的 NFC 技术:

<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>
    
    <tech-list>
        <tech>android.nfc.tech.MifareClassic</tech>
    </tech-list>
    
    <tech-list>
        <tech>android.nfc.tech.MifareUltralight</tech>
    </tech-list>
    
    <tech-list>
        <tech>android.nfc.tech.NfcA</tech>
    </tech-list>
    
    <tech-list>
        <tech>android.nfc.tech.NfcB</tech>
    </tech-list>
    
    <tech-list>
        <tech>android.nfc.tech.NfcF</tech>
    </tech-list>
    
    <tech-list>
        <tech>android.nfc.tech.NfcV</tech>
    </tech-list>
</resources>

2.4、检查 NFC 支持

在代码中检查设备是否支持 NFC:

NfcManager nfcManager = (NfcManager) getSystemService(Context.NFC_SERVICE);
NfcAdapter nfcAdapter = nfcManager.getDefaultAdapter();
if (nfcAdapter == null) {
    // 设备不支持 NFC
    return;
}
if (!nfcAdapter.isEnabled()) {
    // NFC 未开启,引导用户开启
    Intent intent = new Intent(Settings.ACTION_NFC_SETTINGS);
    startActivity(intent);
}

3、NFC 标签读取

3.1、前台调度系统

使用前台调度系统读取 NFC 标签:

private NfcAdapter nfcAdapter;
private PendingIntent pendingIntent;
private IntentFilter[] intentFilters;
private String[][] techLists;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    
    // 初始化 NFC Adapter
    NfcManager nfcManager = (NfcManager) getSystemService(Context.NFC_SERVICE);
    nfcAdapter = nfcManager.getDefaultAdapter();
    
    // 创建 PendingIntent
    pendingIntent = PendingIntent.getActivity(
        this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 
        PendingIntent.FLAG_IMMUTABLE);
    
    // 创建 Intent Filter
    IntentFilter ndef = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
    try {
        ndef.addDataType("*/*");
    } catch (IntentFilter.MalformedMimeTypeException e) {
        e.printStackTrace();
    }
    intentFilters = new IntentFilter[] { ndef };
    
    // 设置技术列表
    techLists = new String[][] {
        new String[] { Ndef.class.getName() },
        new String[] { NfcA.class.getName() }
    };
}
@Override
protected void onResume() {
    super.onResume();
    if (nfcAdapter != null) {
        nfcAdapter.enableForegroundDispatch(this, pendingIntent, intentFilters, techLists);
    }
}
@Override
protected void onPause() {
    super.onPause();
    if (nfcAdapter != null) {
        nfcAdapter.disableForegroundDispatch(this);
    }
}
@Override
protected void onNewIntent(Intent intent) {
    super.onNewIntent(intent);
    
    if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction()) ||
        NfcAdapter.ACTION_TAG_DISCOVERED.equals(intent.getAction())) {
        // 处理 NFC 标签
        processNfcTag(intent);
    }
}

3.2、解析 NDEF 消息

解析 NFC 标签中的 NDEF 消息:

private void processNfcTag(Intent intent) {
    // 获取 NDEF 消息
    Parcelable[] rawMsgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
    
    if (rawMsgs != null) {
        NdefMessage[] msgs = new NdefMessage[rawMsgs.length];
        for (int i = 0; i < rawMsgs.length; i++) {
            msgs[i] = (NdefMessage) rawMsgs[i];
        }
        
        // 解析 NDEF 消息
        for (NdefMessage msg : msgs) {
            for (NdefRecord record : msg.getRecords()) {
                // 解析记录
                parseNdefRecord(record);
            }
        }
    } else {
        // 处理非 NDEF 标签
        Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
        processTag(tag);
    }
}

private void parseNdefRecord(NdefRecord record) {
    // 检查 MIME 类型
    String mimeType = record.toMimeType();
    
    // 解析文本记录
    if (mimeType != null && mimeType.equals("text/plain")) {
        byte[] payload = record.getPayload();
        String text = new String(payload);
        System.out.println("文本内容:" + text);
    }
    
    // 解析 URI 记录
    if (record.getTnf() == NdefRecord.TNF_WELL_KNOWN && 
        Arrays.equals(record.getType(), NdefRecord.RTD_URI)) {
        Uri uri = record.toUri();
        System.out.println("URI:" + uri.toString());
    }
}

3.3、读取标签 ID 和技术

读取 NFC 标签的基本信息:

private void processTag(Tag tag) {
    // 获取标签 ID
    byte[] id = tag.getId();
    String idString = bytesToHexString(id);
    System.out.println("标签 ID:" + idString);
    
    // 获取标签支持的技术
    String[] techList = tag.getTechList();
    for (String tech : techList) {
        System.out.println("支持技术:" + tech);
    }
    
    // 读取 MifareClassic 卡
    MifareClassic mifareClassic = MifareClassic.get(tag);
    if (mifareClassic != null) {
        readMifareClassic(mifareClassic);
    }
}

private String bytesToHexString(byte[] bytes) {
    StringBuilder sb = new StringBuilder();
    for (byte b : bytes) {
        sb.append(String.format("%02X", b));
    }
    return sb.toString();
}

4、NFC 标签写入

4.1、写入 NDEF 数据

向 NFC 标签写入 NDEF 数据:

private void writeNdefTag(Tag tag, String text) {
    // 创建 NDEF 记录
    NdefRecord textRecord = NdefRecord.createTextRecord("en", text);
    
    // 创建 NDEF 消息
    NdefMessage message = new NdefMessage(new NdefRecord[] { textRecord });
    
    // 获取 Ndef 对象
    Ndef ndef = Ndef.get(tag);
    
    if (ndef != null) {
        try {
            // 连接标签
            ndef.connect();
            
            // 检查是否可写
            if (!ndef.isWritable()) {
                System.out.println("标签不可写");
                return;
            }
            
            // 检查容量
            if (ndef.getMaxSize() < message.getByteArrayLength()) {
                System.out.println("标签容量不足");
                return;
            }
            
            // 写入数据
            ndef.writeNdefMessage(message);
            System.out.println("写入成功");
            
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                ndef.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    } else {
        // 格式化并写入
        formatAndWrite(tag, message);
    }
}

4.2、格式化标签

格式化未初始化的 NFC 标签:

private void formatAndWrite(Tag tag, NdefMessage message) {
    NdefFormatable formatable = NdefFormatable.get(tag);
    
    if (formatable != null) {
        try {
            formatable.connect();
            formatable.format(message);
            System.out.println("格式化并写入成功");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                formatable.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

4.3、写入 URI

向 NFC 标签写入 URI:

private void writeUriTag(Tag tag, String uriString) {
    // 创建 URI 记录
    Uri uri = Uri.parse(uriString);
    NdefRecord uriRecord = NdefRecord.createUri(uri);
    
    // 创建 NDEF 消息
    NdefMessage message = new NdefMessage(new NdefRecord[] { uriRecord });
    
    // 写入标签
    writeNdefMessage(tag, message);
}

4.4、写入外部类型数据

写入自定义类型数据:

private void writeExternalTypeTag(Tag tag, String domain, String type, byte[] data) {
    // 创建外部类型记录
    NdefRecord record = NdefRecord.createExternal(domain, type, data);
    
    // 创建 NDEF 消息
    NdefMessage message = new NdefMessage(new NdefRecord[] { record });
    
    // 写入标签
    writeNdefMessage(tag, message);
}

5、实际应用与最佳实践

5.1、智能名片应用

实现 NFC 智能名片功能:

public class NfcBusinessCard {
    private NfcAdapter nfcAdapter;
    
    // 写入名片信息
    public void writeBusinessCard(Tag tag, String name, String phone, String email) {
        // 创建 vCard 数据
        String vCard = "BEGIN:VCARD\n" +
                      "VERSION:3.0\n" +
                      "FN:" + name + "\n" +
                      "TEL:" + phone + "\n" +
                      "EMAIL:" + email + "\n" +
                      "END:VCARD";
        
        // 创建 NDEF 记录
        NdefRecord record = NdefRecord.createMime("text/vcard", vCard.getBytes());
        NdefMessage message = new NdefMessage(new NdefRecord[] { record });
        
        // 写入标签
        writeNdefMessage(tag, message);
    }
    
    // 读取名片信息
    public void readBusinessCard(Intent intent) {
        Parcelable[] rawMsgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
        
        if (rawMsgs != null && rawMsgs.length > 0) {
            NdefMessage msg = (NdefMessage) rawMsgs[0];
            NdefRecord record = msg.getRecords()[0];
            
            if (record.toMimeType().equals("text/vcard")) {
                String vCard = new String(record.getPayload());
                parseVCard(vCard);
            }
        }
    }
    
    private void parseVCard(String vCard) {
        // 解析 vCard 数据
        String[] lines = vCard.split("\n");
        for (String line : lines) {
            if (line.startsWith("FN:")) {
                String name = line.substring(3);
                System.out.println("姓名:" + name);
            } else if (line.startsWith("TEL:")) {
                String phone = line.substring(4);
                System.out.println("电话:" + phone);
            } else if (line.startsWith("EMAIL:")) {
                String email = line.substring(6);
                System.out.println("邮箱:" + email);
            }
        }
    }
}

5.2、智能标签应用

实现智能标签功能:

public class SmartTagManager {
    // 写入智能标签
    public void writeSmartTag(Tag tag, String action, String data) {
        JSONObject json = new JSONObject();
        try {
            json.put("action", action);
            json.put("data", data);
            json.put("timestamp", System.currentTimeMillis());
        } catch (Exception e) {
            e.printStackTrace();
        }
        
        NdefRecord record = NdefRecord.createMime("application/json", json.toString().getBytes());
        NdefMessage message = new NdefMessage(new NdefRecord[] { record });
        
        writeNdefMessage(tag, message);
    }
    
    // 处理智能标签
    public void handleSmartTag(Intent intent) {
        Parcelable[] rawMsgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
        
        if (rawMsgs != null && rawMsgs.length > 0) {
            NdefMessage msg = (NdefMessage) rawMsgs[0];
            NdefRecord record = msg.getRecords()[0];
            
            if (record.toMimeType().equals("application/json")) {
                String jsonStr = new String(record.getPayload());
                try {
                    JSONObject json = new JSONObject(jsonStr);
                    String action = json.getString("action");
                    String data = json.getString("data");
                    
                    // 执行相应操作
                    executeAction(action, data);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
    
    private void executeAction(String action, String data) {
        switch (action) {
            case "open_url":
                // 打开网页
                Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(data));
                startActivity(intent);
                break;
            case "open_app":
                // 打开应用
                Intent launchIntent = getPackageManager().getLaunchIntentForPackage(data);
                if (launchIntent != null) {
                    startActivity(launchIntent);
                }
                break;
            case "wifi_config":
                // 配置 WiFi
                configureWifi(data);
                break;
        }
    }
}

5.3、注意事项

权限处理:

        - 在 AndroidManifest.xml 中声明 NFC 权限

        - 检查设备是否支持 NFC

        - 检查 NFC 是否开启

生命周期管理:

        - 在 onResume() 中启用前台调度

        - 在 onPause() 中禁用前台调度

        - 正确处理 onNewIntent()

性能优化:

        - 避免在主线程执行耗时操作

        - 及时关闭 NFC 标签连接

        - 缓存常用数据

错误处理:

        - 处理标签连接失败

        - 处理写入失败

        - 处理标签容量不足

        - 提供友好的错误提示

用户体验:

        - 提供清晰的 NFC 操作提示

        - 显示标签读取/写入进度

        - 提供操作成功/失败反馈

        - 支持多种标签类型

Android NFC 开发通过 NfcAdapter 和相关 API 实现,可以方便地读取和写入 NFC 标签。掌握 NDEF 格式和 NFC 标签操作方法是 NFC 开发的关键。

在实际开发中:

        - 正确配置 NFC 权限和 Intent Filter

        - 使用前台调度系统处理 NFC 标签

        - 支持多种 NFC 标签类型

        - 提供良好的用户体验和错误处理

        - 注意性能优化和安全性

Android NFC 开发为移动应用提供了丰富的交互方式,通过合理的设计和实现,可以打造出功能强大、用户体验优秀的 NFC 应用。

相关推荐

精选
ViewPager和PagerAdapter、FragmentPagerAdapter、FragmentStatePager
Android

ViewPager和PagerAdapter、FragmentPagerAdapter、FragmentStatePager

ViewPager1、ViewPagerandroidx.viewpager.widget.ViewPager,Android中使用非常广泛的控件,可以说是APP必备:首次打开引导页、页面Banner广告等。常用方法:setAdapter() 设置适配器setOffscreenPageLimit() 设置缓存的页面个数,默认是 1setCurrentItem() 跳转到特定的页面setOnPage

1.1k
获取Android内置WebView内核版本
Android

获取Android内置WebView内核版本

获取Android内置WebView内核版本竟然能遇到这样奇葩的事情,网页用的技术过于新颖,以至于只支持高版本Chromium内核的,低版本安卓系统中内置的内核版本较低,无法加载前端页面。1、设置查看在系统设置里 > 应用 > 应用管理 > 显示系统应用,查看WebView组件:2、页面查看通过WebView发起的网络请求,都会带上浏览器的UA,通常页面都可以通过UA判断浏览器的内核版本。这里有两

1.1w
Android 14适配总结
Android

Android 14适配总结

Android 14适配总结毕业工作至今已经适配了三个Android大版本,从Android 11到Android 12、再到Android 13。2023年,Google即将推出的Android 14,上半年已经开始第一批适配。现在,第四个Android版本已经适配完,总结记录一下。1、Android 14计划Google一般会在2月份对外发布预告,同时放出开发者预览版。“拉通”各大平台、厂商以

1.1w