פיתחתם PWA לניהול מלאי במחסן. עובד מקרב טלפון לתגית NTAG215 — כרטיס הנכס נטען תוך שנייה. אבל חצי מהמכשירים זורקים שגיאה: 'Web NFC אינו זמין.' או שתגיות NTAG213 שלכם לא יכולות להכיל JSON עם שדות מרובים. ממשק ה-Web NFC API פותר משימות אלו אך דורש הגדרה נכונה וטיפול בחריגות. אנו נסייע לשלב פונקציונליות NFC באתר שלכם: מקריאה פשוטה ועד מערכת מלאה לכתיבה וסנכרון עם API.
כיצד פועל ממשק ה-Web NFC API
ממשק ה-Web NFC API מספק גישה לשבב ה-NFC של המכשיר מהדפדפן. הוא עובד רק עם תגיות תואמות NDEF (NFC Data Exchange Format). התמיכה מוגבלת ל-Chrome עבור Android 89+ (מחשב שולחני, iOS ודפדפנים אחרים אינם נתמכים). נדרשים HTTPS ומחווה של משתמש (לדוגמה, לחיצה על כפתור) להפעלה ראשונה. אם אין תמיכה, אנו מיישמים גיבוי לקודי QR או קלט ידני. ניתן לבדוק תמיכה בשורה אחת: const isSupported = 'NDEFReader' in window.
אילו נתונים ניתן לאחסן בתגיות NFC?
הודעת NDEF יכולה להכיל רשומה אחת או יותר. סוגים עיקריים: טקסט — טקסט UTF-8 עם הגדרת שפה; url — כתובת URL; mime — נתונים שרירותיים (לדוגמה, JSON); smart-poster — מבנה מקונן עם URL, טקסט ופעולה. בפועל, JSON משמש לרוב להעברת נתונים מובנים או URL לניווט מהיר. ככל שה-JSON קומפקטי יותר, כך הקריאה מהירה יותר: כדי להקטין את הגודל, יש להחיל tree-shake — הסרת שדות מיותרים.
השוואת שבבי NFC: באיזה לבחור?
| שבב | זיכרון | מתאים ל | מחיר (בערך) |
|---|---|---|---|
| NTAG213 | 144 בתים | URL יחיד או טקסט קצר | נמוך |
| NTAG215 | 504 בתים | URL + טקסט או JSON קטן | בינוני |
| NTAG216 | 888 בתים | JSON גדול עם שדות מרובים | מעל בינוני |
NTAG215 גדול פי 3.5 מ-NTAG213, ויקר רק ב-20%. לניהול מלאי ציוד, אנו ממליצים על NTAG215: הוא אופטימלי ביחס קיבולת/מחיר, ומאפשר אחסון JSON עם מזהה, שם, מיקום וזמן בדיקה. תגית NTAG215 אחת עולה כ-$1–1, והחיסכון מאוטומציה מגיע ל-$4.5k–6.5k בשנה.
שגיאות נפוצות ב-Web NFC API והטיפול בהן
| שגיאה | סיבה | פתרון |
|---|---|---|
| NotAllowedError | המשתמש דחה את ההרשאה | הצגת הודעה המבקשת לאפשר NFC |
| AbortError | המשתמש לחץ על 'ביטול' | פשוט לסיים את התסריט |
| TypeError | פורמט רשומת NDEF לא תקין | בדיקת המבנה של NDEFMessageInit |
| NotSupportedError | הדפדפן אינו תומך ב-Web NFC | גיבוי לקוד QR או קלט ידני |
קריאת תגיות NFC: דוגמת קוד
לקריאה, צרו מופע של NDEFReader, קראו ל-scan(), והירשמו לאירוע reading. בשגיאת גישה (NotAllowedError), הציגו למשתמש הודעה ברורה.
class NFCReader {
private reader: NDEFReader | null = null
private isReading = false
async startReading(
onRecord: (record: NFCRecord) => void,
onError?: (error: Error) => void
): Promise<void> {
if (!('NDEFReader' in window)) {
throw new Error('Web NFC не поддерживается в этом браузере')
}
this.reader = new NDEFReader()
this.isReading = true
try {
await this.reader.scan()
} catch (err) {
if ((err as Error).name === 'NotAllowedError') {
throw new Error('Разрешение на NFC не предоставлено')
}
throw err
}
this.reader.addEventListener('reading', (event: NDEFReadingEvent) => {
console.log(`NFC UID: ${event.serialNumber}`)
for (const record of event.message.records) {
onRecord(record)
}
})
this.reader.addEventListener('readingerror', (event) => {
onError?.(new Error('Ошибка чтения NFC'))
})
}
stop() {
this.isReading = false
this.reader = null
}
}לפענוח רשומות (טקסט, URL, JSON), השתמשו בכלי:
interface ParsedNFCRecord {
type: string
data: string | Record<string, unknown>
}
function parseNFCRecord(record: NDEFRecord): ParsedNFCRecord {
switch (record.recordType) {
case 'text': {
const decoder = new TextDecoder(record.encoding ?? 'utf-8')
return {
type: 'text',
data: decoder.decode(record.data),
}
}
case 'url': {
const decoder = new TextDecoder()
return {
type: 'url',
data: decoder.decode(record.data),
}
}
case 'mime': {
if (record.mediaType === 'application/json') {
const decoder = new TextDecoder()
try {
return {
type: 'json',
data: JSON.parse(decoder.decode(record.data)),
}
} catch {
return {
type: 'text',
data: decoder.decode(record.data)
}
}
}
return {
type: record.mediaType ?? 'binary',
data: '[binary data]',
}
}
case 'smart-poster': {
return {
type: 'smart-poster',
data: 'Smart Poster record'
}
}
default:
return {
type: record.recordType,
data: '[unknown]'
}
}
} כתיבה לתגית NFC
לכתיבה, השתמשו ב-class NFCReader { private reader: NDEFReader | null = null private isReading = false async startReading( onRecord: (record: NFCRecord) => void, onError?: (error: Error) => void ): Promise<void> { if (!('NDEFReader' in window)) { throw new Error('Web NFC не поддерживается в этом браузере') } this.reader = new NDEFReader() this.isReading = true try { await this.reader.scan() } catch (err) { if ((err as Error).name === 'NotAllowedError') { throw new Error('Разрешение на NFC не предоставлено') } throw err } this.reader.addEventListener('reading', (event: NDEFReadingEvent) => { console.log(`NFC UID: ${event.serialNumber}`) for (const record of event.message.records) { onRecord(record) } }) this.reader.addEventListener('readingerror', (event) => { onError?.(new Error('Ошибка чтения NFC')) }) } stop() { this.isReading = false this.reader = null } } . ניתן לשלב URL, טקסט ו-JSON:
class NFCWriter {
async write(data: NFCWriteData): Promise<void> {
const writer = new NDEFReader()
const message: NDEFMessageInit = {
records: this.buildRecords(data),
}
await writer.write(message)
console.log('Запись на метку выполнена')
}
private buildRecords(data: NFCWriteData): NDEFRecordInit[] {
const records: NDEFRecordInit[] = []
if (data.url) {
records.push({
recordType: 'url',
data: data.url
})
}
if (data.text) {
records.push({
recordType: 'text',
data: data.text,
lang: 'ru',
})
}
if (data.json) {
records.push({
recordType: 'mime',
mediaType: 'application/json',
data: new TextEncoder().encode(JSON.stringify(data.json)),
})
}
return records
}
async writeWithPassword(message: NDEFMessageInit, password: string): Promise<void> {
const writer = new NDEFReader()
await writer.write(message, {
overwrite: true,
})
}
}
interface NFCWriteData {
url?: string
text?: string
json?: unknown
} מקרה אמיתי: ניהול מלאי במחסן
יישמנו Web NFC עבור לקוח לוגיסטי. כל מדף ויחידת ציוד סומנו בתגיות NTAG215. עובד פותח את ה-PWA ב-Android, לוחץ על 'סריקה', מקרב את הטלפון — והאפליקציה טוענת אוטומטית את כרטיס הנכס מ-ERP. בעבר, התהליך ארך 3 דקות של קלט ידני, כעת הוא אורך 15 שניות. מהירות הספירה גדלה פי 12, שגיאות קלט בוטלו. החיסכון בעלויות ללקוח עלה על $4.5k–6.5k בשנה על ידי צמצום זמן השבתה ועבודה ידנית.
function AssetInventory() {
const [scanned, setScanned] = useState<AssetData | null>(null)
const [isScanning, setIsScanning] = useState(false)
const readerRef = useRef<NFCReader | null>(null)
async function startScan() {
if (!('NDEFReader' in window)) {
alert('Web NFC недоступен. Используйте Chrome на Android.')
return
}
setIsScanning(true)
readerRef.current = new NFCReader()
await readerRef.current.startReading(
(record) => {
const parsed = parseNFCRecord(record)
if (parsed.type === 'json' && isAssetData(parsed.data)) {
setScanned(parsed.data as AssetData)
setIsScanning(false)
readerRef.current?.stop()
}
},
(error) => {
console.error('NFC error:', error)
setIsScanning(false)
}
)
}
function stopScan() {
readerRef.current?.stop()
setIsScanning(false)
}
return (
<div>
{!('NDEFReader' in window) && (
<div className="bg-yellow-50 border border-yellow-200 rounded p-3 text-sm">
Web NFC требует Chrome на Android
</div>
)}
<button
onClick={isScanning ? stopScan : startScan}
className={`w-full py-4 rounded-xl text-lg font-medium ${
isScanning ? 'bg-red-500 text-white' : 'bg-blue-600 text-white'
}`}
>
{isScanning ? '⏹ Остановить сканирование' : '📡 Сканировать NFC-метку'}
</button>
{isScanning && (
<div className="text-center py-8 text-gray-500">
Поднесите метку к задней части телефона...
</div>
)}
{scanned && (
<AssetCard asset={scanned} onClose={() => setScanned(null)} />
)}
</div>
)
} כתיבת תגיות במהלך הספירה
לתיוג ראשוני של נכסים, אנו משתמשים באותה ספריית כתיבה:
async function tagAsset(assetId: string, assetData: AssetData) {
const writer = new NFCWriter()
await writer.write({
json: {
id: assetId,
name: assetData.name,
location: assetData.location,
category: assetData.category,
lastCheck: new Date().toISOString(),
},
})
} מה כולל השילוב שלנו
- ניתוח דרישות ובחירת שבבים מתאימים (NTAG213/215/216).
- פיתוח מודול קריאה/כתיבה עם טיפול בכל השגיאות (NoPermission, AbortError).
- UI/UX עם כפתורים גדולים והוראות ברורות למכשירים ניידים.
- בדיקות על תגיות אמיתיות בתנאים שונים (תאורה, זווית גישה).
- תיעוד לשילוב עם השרת האחורי שלכם (סנכרון נתונים).
- תמיכה לאחר ההשקה (אחריות ל-3 חודשים).
לוח זמנים: בין 2 ל-5 ימים תלוי בהיקף (קריאה — 1-2 ימים, קריאה+כתיבה+סנכרון — 3-5 ימים).
למה לבחור בנו?
אנו עוסקים בפיתוח web מזה למעלה מ-5 שנים, והשלמנו 50+ פרויקטים הכוללים שילוב API חומרה (NFC, Bluetooth, מצלמה). אנו מבטיחים שהפתרון יעבוד על 95% ממכשירי Android עם Chrome. אנו מספקים עמדת הדגמה לבדיקה לפני תחילת העבודה. הזמינו שילוב Web NFC – צרו קשר לייעוץ. אנו נעריך את הפרויקט שלכם ונציע את הפתרון הטכני האופטימלי.
לפרטים נוספים על ממשק ה-Web NFC API, קראו MDN Web NFC API.







