-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.html
More file actions
287 lines (259 loc) · 12.3 KB
/
index.html
File metadata and controls
287 lines (259 loc) · 12.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>安卓NFC H5 Demo</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { padding: 20px; font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto; }
h1 { color: #333; margin-bottom: 20px; font-size: 22px; }
.btn-group { margin: 20px 0; }
button {
padding: 12px 24px;
margin-right: 10px;
margin-bottom: 10px;
background: #2196F3;
color: white;
border: none;
border-radius: 6px;
cursor: pointer;
font-size: 16px;
}
button:disabled { background: #ccc; cursor: not-allowed; }
#log-container {
margin-top: 20px;
padding: 15px;
border: 1px solid #eee;
border-radius: 6px;
min-height: 300px;
max-height: 400px;
overflow-y: auto;
font-size: 14px;
line-height: 1.6;
}
.log-info { color: #666; }
.log-success { color: #4CAF50; }
.log-error { color: #F44336; }
.log-warning { color: #FF9800; }
</style>
</head>
<body>
<h1>安卓NFC H5 Demo(读写测试)</h1>
<div class="btn-group">
<button id="checkSupport">1. 检测NFC支持性</button>
<button id="startRead">2. 读取NFC标签</button>
<button id="startWrite">3. 写入NFC标签</button>
<button id="stopScan">4. 停止监听</button>
</div>
<div id="log-container"></div>
<script>
// ========== 全局变量 ==========
const logContainer = document.getElementById('log-container');
let ndefReader = null; // NFC实例
let isScanning = false; // 是否正在扫描
// ========== 工具函数:日志输出 ==========
function log(message, type = 'info') {
const logItem = document.createElement('div');
logItem.className = `log-${type}`;
logItem.innerHTML = `[${new Date().toLocaleTimeString()}] ${message}`;
logContainer.appendChild(logItem);
// 自动滚动到底部
logContainer.scrollTop = logContainer.scrollHeight;
// 控制台同步输出
console[type === 'error' ? 'error' : type === 'success' ? 'log' : type === 'warning' ? 'warn' : 'log'](message);
}
// ========== 步骤1:检测NFC支持性 ==========
document.getElementById('checkSupport').addEventListener('click', () => {
log('开始检测NFC环境...');
// 1. 检测是否为移动端(电脑端无NFC)
if (!/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) {
log('❌ 当前设备非移动端,无法测试NFC', 'error');
disableAllButtons();
return;
}
// 2. 检测是否为安卓(iOS仅支持读取,且限制多)
const isAndroid = /Android/i.test(navigator.userAgent);
if (!isAndroid) {
log('⚠️ 检测到iOS设备,仅支持读取NDEF标签,写入功能禁用', 'warning');
document.getElementById('startWrite').disabled = true;
} else {
log('✅ 检测到Android设备,支持NFC读写', 'success');
}
// 3. 检测NDEFReader API是否存在(核心)
if (!('NDEFReader' in window)) {
log('❌ 当前浏览器不支持Web NFC API', 'error');
log('💡 原因:可能是非Chrome/Edge浏览器、非HTTPS/localhost环境、浏览器禁用了Web NFC', 'warning');
disableAllButtons();
return;
} else {
log('✅ 浏览器支持Web NFC API', 'success');
}
// 4. 检测是否为安全上下文(HTTPS/localhost)
if (!window.isSecureContext) {
log('⚠️ 当前环境非安全上下文(非HTTPS/localhost),NFC API可能无法正常工作', 'warning');
log('💡 建议使用localhost或HTTPS环境测试', 'warning');
} else {
log('✅ 当前环境为安全上下文(HTTPS/localhost)', 'success');
}
log('✅ 环境检测完成,可开始测试NFC读写', 'success');
});
// ========== 步骤2:读取NFC标签 ==========
document.getElementById('startRead').addEventListener('click', async () => {
if (isScanning) {
log('⚠️ 已在扫描中,请勿重复点击', 'warning');
return;
}
log('🔍 开始扫描NFC标签,请将标签靠近手机背部NFC感应区(通常在摄像头附近)');
try {
// 创建NFC实例
ndefReader = new NDEFReader();
isScanning = true;
document.getElementById('startRead').disabled = true;
document.getElementById('stopScan').disabled = false;
// 启动扫描(触发权限请求)
await ndefReader.scan();
log('✅ 扫描已启动,等待检测NFC标签...', 'success');
// 监听标签读取成功事件
ndefReader.onreading = (event) => {
log('📌 检测到NFC标签,开始解析数据...');
const { records } = event.message; // 标签中的NDEF记录数组
if (records.length === 0) {
log('⚠️ NFC标签无数据', 'warning');
return;
}
// 遍历解析所有记录
records.forEach((record, index) => {
log(`--- 解析第${index+1}条记录 ---`);
parseNDEFRecord(record);
});
};
// 监听读取错误事件
ndefReader.onreadingerror = (event) => {
log(`❌ 读取NFC标签失败:${event.message || '标签格式不支持/标签损坏'}`, 'error');
};
} catch (error) {
log(`❌ 启动扫描失败:${error.message}`, 'error');
// 常见错误处理
if (error.message.includes('Permission denied')) {
log('💡 请在手机设置中授予浏览器NFC权限,并确保NFC开关已开启', 'warning');
} else if (error.message.includes('NFC permission denied')) {
log('💡 浏览器请求NFC权限被拒绝,请重新加载页面并允许权限', 'warning');
} else if (error.message.includes('No NFC adapter')) {
log('💡 手机未开启NFC开关,请前往设置开启', 'warning');
}
resetScanState();
}
});
// ========== 步骤3:写入NFC标签 ==========
document.getElementById('startWrite').addEventListener('click', async () => {
log('✍️ 准备写入NFC标签,请将空白NDEF标签靠近手机背部NFC感应区');
try {
ndefReader = new NDEFReader();
// 定义要写入的NDEF数据(支持多类型)
const writeData = {
records: [
// 记录1:文本类型(核心)
{
recordType: 'text', // 记录类型:文本
data: 'NFC Demo 测试内容', // 写入的文本
encoding: 'utf-8', // 编码
lang: 'zh-CN' // 语言
},
// 可选:记录2:URL类型
// {
// recordType: 'url',
// data: 'https://www.example.com'
// },
// 可选:记录3:JSON(MIME类型)
// {
// recordType: 'mime',
// mediaType: 'application/json',
// data: JSON.stringify({ name: 'NFC测试', time: new Date().toLocaleString() })
// }
]
};
// 写入数据
await ndefReader.write(writeData);
log('✅ NFC标签写入成功!可点击「读取NFC标签」验证', 'success');
} catch (error) {
log(`❌ 写入NFC标签失败:${error.message}`, 'error');
// 常见写入错误处理
if (error.message.includes('not writable')) {
log('💡 标签为只读状态,请更换空白可写的NDEF标签', 'warning');
} else if (error.message.includes('No tag found')) {
log('💡 未检测到NFC标签,请确保标签靠近感应区', 'warning');
} else if (error.message.includes('Tag lost')) {
log('💡 标签离开感应区过快,请重新尝试', 'warning');
}
}
});
// ========== 步骤4:停止NFC监听 ==========
document.getElementById('stopScan').addEventListener('click', () => {
if (!isScanning) {
log('⚠️ 未在扫描中,无需停止', 'warning');
return;
}
log('🛑 停止NFC扫描...');
resetScanState();
log('✅ NFC扫描已停止', 'success');
});
// ========== 辅助函数:解析NDEF记录 ==========
function parseNDEFRecord(record) {
switch (record.recordType) {
case 'text':
// 解析文本
const textDecoder = new TextDecoder(record.encoding || 'utf-8');
const text = textDecoder.decode(record.data);
log(`✅ 文本类型:${text}`, 'success');
break;
case 'url':
// 解析URL
const urlDecoder = new TextDecoder();
const url = urlDecoder.decode(record.data);
log(`✅ URL类型:${url}`, 'success');
break;
case 'mime':
// 解析MIME类型(如JSON)
const mimeDecoder = new TextDecoder();
const mimeData = mimeDecoder.decode(record.data);
log(`✅ MIME类型(${record.mediaType}):${mimeData}`, 'success');
break;
case 'empty':
log('⚠️ 空记录', 'warning');
break;
default:
log(`⚠️ 不支持的记录类型:${record.recordType}`, 'warning');
// 输出原始数据(十六进制)
log(`原始数据(十六进制):${Array.from(record.data).map(b => b.toString(16).padStart(2, '0')).join(' ')}`, 'info');
break;
}
}
// ========== 辅助函数:禁用所有按钮 ==========
function disableAllButtons() {
document.getElementById('startRead').disabled = true;
document.getElementById('startWrite').disabled = true;
document.getElementById('stopScan').disabled = true;
}
// ========== 辅助函数:重置扫描状态 ==========
function resetScanState() {
if (ndefReader) {
// 清空监听事件
ndefReader.onreading = null;
ndefReader.onreadingerror = null;
ndefReader = null;
}
isScanning = false;
document.getElementById('startRead').disabled = false;
document.getElementById('stopScan').disabled = true;
}
// ========== 页面卸载时停止扫描 ==========
window.addEventListener('beforeunload', () => {
if (isScanning) {
resetScanState();
log('页面卸载,已停止NFC监听', 'info');
}
});
</script>
</body>
</html>