更新记录
1.4.9(2026-06-08)
-
Android 端
- 移除未使用参数,消除编译警告
- stopListenNFC 增加保护逻辑,防止中断正在进行的读写操作
-
iOS 端
- 添加完整的 Swift 类型声明,提高类型安全性
- 统一错误对象创建方式
-
HarmonyOS 端
- openNFCSettings 三级降级方案: a. ohos.settings.action.NFC_SETTINGS b. ohos.settings.action.SETTINGS c. ohos.settings.action.WIRELESS_SETTINGS
- 兼容所有鸿蒙设备厂商
-
接口定义
- NFCError.errCode 改为必填,保证错误码一致
1.4.8(2026-06-01)
harmony 平台警告消除以及兼容性问题修复
1.4.7(2026-03-03)
- 修复ios端大小端问题
平台兼容性
uni-app(4.87)
| Vue2 | Vue2插件版本 | Vue3 | Vue3插件版本 | Chrome | Safari | app-vue | app-vue插件版本 | app-nvue | app-nvue插件版本 | Android | Android插件版本 | iOS | iOS插件版本 | 鸿蒙 | 鸿蒙插件版本 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| √ | 1.4.9 | √ | 1.4.9 | - | - | √ | 1.4.9 | √ | 1.4.9 | 5.0 | 1.4.9 | 13 | 1.4.9 | 12 | 1.4.9 |
| 微信小程序 | 支付宝小程序 | 抖音小程序 | 百度小程序 | 快手小程序 | 京东小程序 | 鸿蒙元服务 | QQ小程序 | 飞书小程序 | 小红书小程序 | 快应用-华为 | 快应用-联盟 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| - | - | - | - | - | - | - | - | - | - | - | - |
uni-app x(4.87)
| Chrome | Safari | Android | iOS | 鸿蒙 | 微信小程序 |
|---|---|---|---|---|---|
| - | - | - | - | - | - |
ry-nfc
UniApp / UniApp X 通用 NFC 读写插件,支持 Android NDEF 协议和 iOS ISO14443 + ISO15693 双协议。
平台支持
| 平台 | 最低版本 | uni-app | uni-app x |
|---|---|---|---|
| Android | API 21+ | ✅ | ✅ |
| iOS | 13.0+ | ✅ | ✅ |
安装
将 ry-nfc 目录复制到项目 uni_modules 目录下。
配置
Android
在 manifest.json 中添加 NFC 权限:
{
"app-plus": {
"distribute": {
"android": {
"permissions": [
"<uses-permission android:name=\"android.permission.NFC\"/>",
"<uses-feature android:name=\"android.hardware.nfc\" android:required=\"true\"/>"
]
}
}
}
}
iOS
- 在 HBuilderX 中勾选 NFC 模块
- Apple Developer 后台开启 NFC Tag Reading 能力
Info.plist添加:
<key>NFCReaderUsageDescription</key>
<string>需要NFC权限用于读写NFC标签</string>
使用示例
uni-app 模式 (.vue)
<template>
<view class="container">
<view class="header">
<text class="title">NFC 读写测试</text>
<text class="status" :class="{ active: status.isReady }">
{{ status.isReady ? '已就绪' : '未初始化' }}
</text>
</view>
<!-- 状态 -->
<view class="card">
<text class="card-title">设备状态</text>
<view class="info-row">
<text>NFC支持: {{ status.isSupported ? '是' : '否' }}</text>
</view>
<view class="info-row">
<text>NFC开启: {{ status.isEnabled ? '是' : '否' }}</text>
</view>
<view class="info-row">
<text>监听中: {{ status.isListening ? '是' : '否' }}</text>
</view>
</view>
<!-- 基础操作 -->
<view class="card">
<text class="card-title">基础操作</text>
<view class="btn-row">
<button class="btn primary" @click="doInit" :disabled="status.isReady">初始化</button>
<button class="btn" @click="doRefresh">刷新状态</button>
</view>
</view>
<!-- 读取 -->
<view class="card">
<text class="card-title">读取标签</text>
<view class="btn-row">
<button class="btn primary" @click="doRead" :disabled="!status.isReady || loading">
{{ loading && op === 'read' ? '扫描中...' : '读取' }}
</button>
<button class="btn" @click="toggleListen" :disabled="!status.isReady">
{{ status.isListening ? '停止监听' : '开始监听' }}
</button>
</view>
</view>
<!-- 写入 -->
<view class="card">
<text class="card-title">写入标签</text>
<view class="input-row">
<input v-model="textInput" class="input" placeholder="输入文本" />
<button class="btn primary small" @click="doWriteText" :disabled="!status.isReady || !textInput">写入</button>
</view>
<view class="input-row">
<input v-model="uriInput" class="input" placeholder="输入URI" />
<button class="btn primary small" @click="doWriteUri" :disabled="!status.isReady || !uriInput">写入</button>
</view>
</view>
<!-- 结果 -->
<view class="card" v-if="result">
<text class="card-title">读取结果</text>
<view class="info-row" style="word-break: break-all;">{{ JSON.stringify(result) }}</view>
</view>
<!-- 底部 -->
<view class="footer">
<button class="btn" @click="doCancel" :disabled="!loading">取消</button>
<button class="btn" @click="doClose">关闭</button>
</view>
</view>
</template>
<script>
// uni-app 模式使用 JS/TS
import {
initNFC,
getNFCStatus,
readNDEF,
writeText,
writeUri,
startListenNFC,
stopListenNFC,
closeNFC,
cancelOperation
} from '@/uni_modules/ry-nfc';
export default {
data() {
return {
status: {
isReady: false,
isListening: false,
isSupported: false,
isEnabled: false
},
loading: false,
op: '',
textInput: '',
uriInput: 'https://',
result: null
};
},
onLoad() {
try {
this.doRefresh();
} catch (e) {
console.log('onLoad doRefresh error:', e);
}
},
onUnload() {
closeNFC();
},
methods: {
doRefresh() {
try {
this.status = getNFCStatus();
} catch (e) {
console.log('getNFCStatus error:', e);
this.status = {
isReady: false,
isListening: false,
isSupported: false,
isEnabled: false
};
}
},
async doInit() {
if (!this.status.isSupported) {
uni.showToast({ title: '不支持NFC' });
return;
}
try {
await initNFC();
uni.showToast({ title: '初始化成功' });
this.doRefresh();
} catch (e) {
console.log('initNFC error:', JSON.stringify(e));
let msg = '初始化失败';
if (e && typeof e === 'object') {
msg = e.errMsg || e.message || JSON.stringify(e);
} else if (typeof e === 'string') {
msg = e;
}
console.log('初始化失败===>',msg);
// uni.showToast({ title: msg, icon: 'none' });
}
},
async doRead() {
if (!this.status.isSupported) {
uni.showToast({ title: '不支持NFC' });
return;
}
this.loading = true;
this.op = 'read';
try {
uni.showLoading({ title: '请靠近标签' });
const res = await readNDEF();
console.log('readNDEF====>', JSON.stringify(res));
uni.hideLoading();
this.result = res;
} catch (e) {
uni.hideLoading();
console.log('readNDEF error:', JSON.stringify(e));
let msg = e && e.errMsg ? e.errMsg : '读取失败';
uni.showToast({ title: msg, icon: 'none' });
} finally {
this.loading = false;
this.op = '';
}
},
toggleListen() {
if (!this.status.isSupported) {
uni.showToast({ title: '不支持NFC' });
return;
}
if (this.status.isListening) {
stopListenNFC();
} else {
startListenNFC((res) => {
if (res.errMsg) {
console.error(res.errMsg);
return;
}
this.result = res;
});
}
this.doRefresh();
},
async doWriteText() {
if (!this.status.isSupported) {
uni.showToast({ title: '不支持NFC' });
return;
}
this.loading = true;
this.op = 'writeText';
try {
uni.showLoading({ title: '请靠近标签' });
await writeText({ text: this.textInput });
uni.hideLoading();
uni.showToast({ title: '写入成功' });
} catch (e) {
uni.hideLoading();
console.log('writeText error:', JSON.stringify(e));
let msg = e && e.errMsg ? e.errMsg : '写入失败';
uni.showToast({ title: msg, icon: 'none' });
} finally {
this.loading = false;
this.op = '';
}
},
async doWriteUri() {
if (!this.status.isSupported) {
uni.showToast({ title: '不支持NFC' });
return;
}
this.loading = true;
this.op = 'writeUri';
try {
uni.showLoading({ title: '请靠近标签' });
await writeUri({ uri: this.uriInput });
uni.hideLoading();
uni.showToast({ title: '写入成功' });
} catch (e) {
uni.hideLoading();
console.log('writeUri error:', JSON.stringify(e));
let msg = e && e.errMsg ? e.errMsg : '写入失败';
uni.showToast({ title: msg, icon: 'none' });
} finally {
this.loading = false;
this.op = '';
}
},
doCancel() {
cancelOperation();
this.loading = false;
this.op = '';
uni.hideLoading();
},
doClose() {
if (!this.status.isSupported) {
uni.showToast({ title: '不支持NFC' });
return;
}
closeNFC();
this.doRefresh();
}
}
};
</script>
<style>
.container {
padding: 20rpx;
background-color: #f5f5f5;
}
.header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 20rpx;
}
.title {
font-size: 36rpx;
font-weight: bold;
}
.status {
padding: 8rpx 16rpx;
border-radius: 20rpx;
background-color: #ccc;
color: #fff;
font-size: 24rpx;
}
.status.active {
background-color: #4caf50;
}
.card {
background-color: #fff;
border-radius: 12rpx;
padding: 20rpx;
margin-bottom: 20rpx;
}
.card-title {
font-size: 28rpx;
font-weight: bold;
margin-bottom: 16rpx;
}
.info-row {
padding: 8rpx 0;
}
.content {
color: #2196f3;
font-weight: bold;
}
.raw {
font-size: 22rpx;
color: #999;
word-break: break-all;
}
.btn-row {
display: flex;
gap: 16rpx;
}
.input-row {
display: flex;
gap: 16rpx;
margin-bottom: 16rpx;
}
.btn {
flex: 1;
height: 80rpx;
border-radius: 8rpx;
background-color: #e0e0e0;
font-size: 28rpx;
}
.btn.primary {
background-color: #2196f3;
color: #fff;
}
.btn.small {
flex: none;
width: 120rpx;
}
.input {
flex: 1;
height: 80rpx;
padding: 0 16rpx;
border: 1rpx solid #ddd;
border-radius: 8rpx;
}
.footer {
display: flex;
gap: 16rpx;
padding: 20rpx 0;
}
</style>
<script>
import {
initNFC,
readNDEF,
writeText,
closeNFC,
openNFCSettings
} from '@/uni_modules/ry-nfc';
export default {
async onLoad() {
try {
await initNFC();
console.log('NFC 初始化成功');
} catch (e) {
console.error(e.errMsg);
}
},
onUnload() {
closeNFC();
},
methods: {
async read() {
try {
const res = await readNDEF();
console.log('类型:', res.type);
console.log('内容:', res.content);
} catch (e) {
console.error(e.errMsg);
}
}
}
};
</script>
uni-app x 模式 (.uvue)
<script lang="uts">
import {
initNFC,
readNDEF,
writeText,
closeNFC,
NFCReadResult,
NFCError,
openNFCSettings,
} from '@/uni_modules/ry-nfc';
export default {
async onLoad() {
try {
await initNFC();
console.log('NFC 初始化成功');
} catch (e) {
const err = e as NFCError;
console.error(err.errMsg);
}
},
onUnload() {
closeNFC();
},
methods: {
async read() {
try {
const res = await readNDEF();
console.log('类型:', res.type);
console.log('内容:', res.content);
} catch (e) {
const err = e as NFCError;
console.error(err.errMsg);
}
}
}
};
</script>
API 文档
initNFC()
初始化 NFC 模块。
initNFC(): Promise<NFCResult>
type NFCResult = {
code: number // 0=成功
msg: string
}
getNFCStatus()
获取 NFC 状态。
getNFCStatus(): NFCStatus
type NFCStatus = {
isReady: boolean // 已初始化
isListening: boolean // 监听中
isSupported: boolean // 设备支持
isEnabled: boolean // 已开启
}
readNDEF()
读取 NFC 标签。
readNDEF(): Promise<NFCReadResult>
type NFCReadResult = {
type: string // text | uri | unknown
content: string // 内容
raw: string // 原始数据(十六进制)
tagId: string // 标签ID
}
writeText(options)
写入文本。
writeText(options: WriteTextOptions): Promise<NFCResult>
type WriteTextOptions = {
text: string // 文本内容
language?: string // 语言代码,默认 "en"
}
writeUri(options)
写入 URI。
writeUri(options: WriteUriOptions): Promise<NFCResult>
type WriteUriOptions = {
uri: string // http/https/tel/mailto
}
startListenNFC(callback)
开始监听。
startListenNFC(callback: NFCListenCallback): void
type NFCListenCallback = (result: NFCReadResult | NFCError) => void
stopListenNFC()
停止监听。
stopListenNFC(): void
closeNFC()
关闭 NFC 模块。
closeNFC(): void
cancelOperation()
取消当前操作。
cancelOperation(): void
错误处理
type NFCError = {
errCode?: number
errMsg: string
}
| 错误信息 | 说明 |
|---|---|
| 设备不支持NFC | 无NFC硬件 |
| 请开启NFC功能 | NFC未开启 |
| 请先调用 initNFC 初始化 | 未初始化 |
| 标签不支持NDEF协议 | 非NDEF标签 |
| 标签为只读状态 | 无法写入 |
| 会话失效 | iOS超时 |
目录结构
ry-nfc/
├── index.uts # 入口 + 类型声明
├── interface.uts # 内部类型
├── package.json # 配置
├── README.md # 文档
└── utssdk/
├── app-android/
│ ├── index.uts # Android 实现
│ └── config.json # Android 配置
└── app-ios/
├── index.uts # iOS 实现
└── config.json # iOS 配置
└── app-harmony/
├── index.uts # HarmonyOS 实现
└── config.json # HarmonyOS 配置
注意事项
- 必须在真机上测试
- 标签距离建议 1-2cm
- 页面销毁时调用
closeNFC() - iOS 会话有超时限制(约60秒)
- Android 仅支持 NDEF 协议标签
版本历史
- 1.3.0: 同时支持 uni-app 和 uni-app x
- 1.2.0: 重构,符合 UTS 插件规范
- 1.1.0: 添加类型定义
- 1.0.0: 初始版本

收藏人数:
购买普通授权版(
试用
赞赏(0)
下载 33
赞赏 0
下载 12436343
赞赏 1934
赞赏
京公网安备:11010802035340号