Реализация Web NFC API на сайте

Наша компания занимается разработкой, поддержкой и обслуживанием сайтов любой сложности. От простых одностраничных сайтов до масштабных кластерных систем построенных на микро сервисах. Опыт разработчиков подтвержден сертификатами от вендоров.

Разработка и обслуживание любых видов сайтов:

Информационные сайты или веб-приложения
Сайты визитки, landing page, корпоративные сайты, онлайн каталоги, квиз, промо-сайты, блоги, новостные ресурсы, информационные порталы, форумы, агрегаторы
Сайты или веб-приложения электронной коммерции
Интернет-магазины, B2B-порталы, маркетплейсы, онлайн-обменники, кэшбэк-сайты, биржи, дропшиппинг-платформы, парсеры товаров
Веб-приложения для управления бизнес-процессами
CRM-системы, ERP-системы, корпоративные порталы, системы управления производством, парсеры информации
Сайты или веб-приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, конструкторы сайтов, порталы предоставления электронных услуг, видеохостинги, тематические порталы

Это лишь некоторые из технических типов сайтов, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента

Предлагаемые услуги
Показано 1 из 1 услугВсе 2065 услуг
Реализация Web NFC API на сайте
Средняя
от 1 рабочего дня до 3 рабочих дней
Часто задаваемые вопросы

Наши компетенции:

Этапы разработки

Последние работы

  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1262
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1171
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    874
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1094
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    831
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Разработка веб-сайта для компании ФИКСПЕР
    851

Реализация Web NFC API на сайте

Web NFC API позволяет читать и записывать NFC-метки прямо из браузера на Android-устройствах. Применения: инвентаризация (поднёс телефон к оборудованию — открылась карточка в системе), регистрация на мероприятиях, считывание информации с браслетов в гостиницах, умные маркетинговые вывески.

Поддержка

Chrome для Android 89+. Desktop Chrome, Firefox, Safari — не поддерживают. Только HTTPS. Только user gesture при первом запуске.

const isSupported = 'NDEFReader' in window

Если поддержки нет — fallback на QR-коды или ручной ввод.

Чтение 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() {
    // AbortController для остановки сканирования
    this.isReading = false
    this.reader = null
  }
}

Декодирование записей NDEF

NFC-метка содержит NDEF (NFC Data Exchange Format) сообщения с одной или несколькими записями:

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) }
        }
      }
      // Бинарные данные — возвращаем как ArrayBuffer
      return {
        type: record.mediaType ?? 'binary',
        data: '[binary data]',
      }
    }

    case 'smart-poster': {
      // Smart poster содержит вложенные записи
      return { type: 'smart-poster', data: 'Smart Poster record' }
    }

    default:
      return { type: record.recordType, data: '[unknown]' }
  }
}

Запись на NFC-метку

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> {
    // Защита метки паролем — зависит от типа чипа (NTAG213/215/216)
    // Требует записи специфических страниц напрямую через бинарный write
    const writer = new NDEFReader()
    await writer.write(message, {
      overwrite: true,
    })
  }
}

interface NFCWriteData {
  url?: string
  text?: string
  json?: unknown
}

Инвентаризация оборудования

Реальный сценарий: каждый актив помечен NFC-меткой с JSON, сотрудник сканирует — открывается карточка:

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(),
    },
  })
}

Что делаем

Реализуем сканирование NFC-меток с декодированием NDEF-записей, запись JSON-данных на метки, обработку ошибок и отсутствия поддержки. Строим UI с понятным UX для мобильных (большие кнопки, чёткие инструкции «поднесите телефон»). Тестируем с реальными NFC-метками (NTAG213/215/216 — наиболее распространены).

Срок: чтение и отображение данных с метки — 1 день. Полноценная система инвентаризации (чтение + запись + синхронизация с API) — 3–4 дня.