Uniapp实现Android平台NFC读取IC卡数据的实战指南

1. 为什么要在Uniapp里折腾NFC?

大家好,我是老张,一个在移动开发领域摸爬滚打了十来年的老兵。这些年,我见过太多开发者一听到“NFC”和“Uniapp”这两个词放在一起,第一反应就是摇头:“这能行吗?Uniapp不是搞前端的吗?” 我当初也是这么想的,直到一个真实的项目需求砸过来——客户需要一款用于内部资产盘点的App,要求员工用手机贴近资产标签(IC卡)就能自动读取并登记信息。如果走原生开发,安卓和iOS得各搞一套,成本和时间都扛不住。于是,我们硬着头皮在Uniapp里探索NFC的可能性。

实测下来,这条路不仅走得通,而且对于很多特定场景(比如门禁、工牌识别、物流标签读取)来说,性价比极高。Uniapp的跨端能力让你用一套代码覆盖安卓和iOS(尽管iOS的NFC权限更严格),而借助Android平台的Native.js能力,我们可以直接调用系统的NFC API,实现读取IC卡UID(唯一标识符)甚至扇区数据的功能。这篇文章,我就把自己踩过的坑、总结出来的最佳实践,手把手分享给你。无论你是想做一个简单的打卡应用,还是复杂的加密卡数据读取,相信都能找到可落地的方案。

2. 开发前的核心准备:权限、设备与原理

在动手写代码之前,有几件事必须门儿清,不然很容易做无用功。这就像做饭前,你得先看看厨房有没有锅和灶。

2.1 你的手机和IC卡“对话”吗?

首先,不是所有手机都有NFC功能。通常中高端机型配备得比较多。其次,更重要的是IC卡的类型。我们常说的IC卡,比如门禁卡、公交卡,大多属于Mifare Classic系列(简称M1卡),这也是我们这篇文章主要对付的目标。你的手机NFC模块必须支持读写这类卡的协议。好消息是,现在绝大部分安卓手机的NFC都兼容Mifare Classic。

如何确认呢?你可以先下载一个叫“NFC Tools”的App,用它贴近你的IC卡,如果能识别出类型是“Mifare Classic”或“NFC-A”,那就没问题。这一步千万别省,我见过有开发者代码写了一天,最后发现测试卡是ID卡(低频卡,手机NFC根本不支持),白白浪费了时间。

2.2 在Uniapp里给NFC开“通行证”

想让你的Uniapp应用访问手机的NFC硬件,必须在配置文件中声明权限。打开你项目根目录下的 manifest.json 文件,找到 app-plus -> distribute -> android 节点,在里面添加权限配置。光有权限声明还不够,对于安卓系统,尤其是比较新的版本,你还需要在应用启动时动态请求这些权限。

// manifest.json 部分配置
"app-plus": {
  "distribute": {
    "android": {
      "permissions": [
        "android.permission.NFC",
        "android.permission.VIBRATE" // 可选,用于读卡成功时震动反馈
      ],
      "features": [
        "android.hardware.nfc" // 声明应用需要NFC硬件支持
      ]
    }
  }
}

2.3 NFC读卡的核心原理:前台调度系统

这是安卓平台NFC开发中最关键的一个概念,理解了它,代码就看懂了一半。想象一下,你的手机同时安装了支付宝、微信和你自己开发的App,都支持NFC。当用户贴上一张公交卡时,手机怎么知道该唤醒哪个应用呢?

安卓系统提供了一个叫**前台调度(Foreground Dispatch)**的机制。它允许你的应用在处于前台(即用户正在使用你的App界面)时,拥有最高的NFC事件优先级。你通过代码告诉系统:“嘿,我现在在前台,如果检测到NFC标签,先交给我来处理!” 这样,当IC卡贴近时,系统就会把标签信息直接发送给你的应用,而不是弹出应用选择器。

我们的核心代码,其实就是围绕如何启动和停止这个“前台调度”来展开的。在应用页面显示时启动它,在页面隐藏或应用暂停时关闭它,这样才能保证良好的用户体验和电量管理。

3. 从零开始:封装一个健壮的NFC工具类

直接在网上找的代码片段往往只解决了“读出来”的问题,但实际项目中,稳定性、错误处理和用户体验同样重要。下面我分享一个我优化过多次的NFC工具类,它包含了设备检测、前台调度管理、数据读取和基本的错误处理。

3.1 工具类骨架与初始化

我们创建一个单独的JS文件,比如 nfc.js,放在项目的 common 目录下。这样做的好处是业务逻辑和NFC底层调用分离,方便维护和复用。

// common/nfc.js
// 导入必要的Android类
let Context = plus.android.importClass("android.content.Context");
let NfcAdapter = plus.android.importClass("android.nfc.NfcAdapter");
let Intent = plus.android.importClass("android.content.Intent");
let PendingIntent = plus.android.importClass("android.app.PendingIntent");
let IntentFilter = plus.android.importClass("android.content.IntentFilter");

// 定义支持的NFC技术类型列表,覆盖常见的IC卡类型
const TECH_LISTS_ARRAY = [
    ["android.nfc.tech.IsoDep"],
    ["android.nfc.tech.NfcA"], // 绝大多数M1卡属于NfcA
    ["android.nfc.tech.NfcB"],
    ["android.nfc.tech.NfcF"],
    ["android.nfc.tech.NfcV"],
    ["android.nfc.tech.Ndef"],
    ["android.nfc.tech.NdefFormatable"],
    ["android.nfc.tech.MifareClassic"], // 关键!用于M1卡
    ["android.nfc.tech.MifareUltralight"]
];

const NfcManager = {
    data: {
        nfcAdapter: null,
        mainActivity: null,
        pendingIntent: null,
        intentFilters: null,
        isDispatchEnabled: false,
        callback: null // 用于接收读卡结果
    },

    // 初始化:检查NFC并获取适配器
    init: function() {
        return new Promise((resolve, reject) => {
            try {
                this.data.mainActivity = plus.android.runtimeMainActivity();
                let nfcManager = this.data.mainActivity.getSystemService(Context.NFC_SERVICE);
                this.data.nfcAdapter = NfcAdapter.getDefaultAdapter(this.data.mainActivity);

                if (!this.data.nfcAdapter) {
                    reject(new Error("设备不支持NFC功能"));
                
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值