שילוב NFC: פתרונות ל-iOS ואנדרואיד עם מגבלות פלטפורמה
האפליקציה הניידת לא מזהה תג NFC? סשן iOS נסגר לפני שהמשתמש מקרב את התג? באנדרואיד, אפליקציות תשלום מיירטות NFC? אלה תרחישים אופייניים שאנו נתקלים בהם במהלך שילוב NFC. ב-80% מהמקרים, הבעיה נפתרת על ידי הגדרת סשן נכונה או בחירת המצב המתאים. הצוות שלנו, עם ניסיון של 10+ שנים בפיתוח מובייל, יכול לעזור לכם להימנע מהמלכודות הללו — מתוך 20+ פרויקטי NFC צברנו פתרונות מוכחים לכל בעיה.
NFC באפליקציה ניידת אינו רק קריאת תגים. משימות אמיתיות כוללות אימות כרטיסים, אמולציית כרטיסי תחבורה, קריאת דרכונים (ePassport), ועבודה עם MIFARE Classic. כל פלטפורמה מטילה אילוצים משלה: iOS דורשת הפעלת סשן מפורשת, אנדרואיד דורשת התמודדות עם עדיפויות של אפליקציות תשלום. בעזרת הניסיון שלנו, תקצרו את זמן ניפוי ה-NFC ב-40%.
iOS: Core NFC ועבודה עם תגים
iOS תומכת ב-NFC מאז iPhone 7 (iOS 11), אך קריאת תגי NDEF ולא-NDEF מלאה הופיעה רק ב-iOS 13. כתיבה לתגים הגיעה ב-iOS 13. קריאת תגים ברקע (ללא הפעלת סשן מפורשת) הגיעה ב-iOS 14.
מחלקות מפתח: NFCNDEFReaderSession עבור תגי NDEF, NFCTagReaderSession עבור תגים לא-NDEF (ISO 7816, ISO 15693, FeliCa, MIFARE).
import CoreNFC
class NFCManager: NSObject, NFCNDEFReaderSessionDelegate {
var session: NFCNDEFReaderSession?
func startReading() {
guard NFCNDEFReaderSession.readingAvailable else {
// устройство не поддерживает NFC или NFC отключён
return
}
session = NFCNDEFReaderSession(delegate: self, queue: nil, invalidateAfterFirstRead: true)
session?.alertMessage = "Поднесите NFC-метку"
session?.begin()
}
func readerSession(_ session: NFCNDEFReaderSession, didDetectNDEFs messages: [NFCNDEFMessage]) {
for message in messages {
for record in message.records {
if record.typeNameFormat == .nfcWellKnown, let type = String(data: record.type, encoding: .utf8), type == "T" {
// текстовая запись
let payload = record.payload
// первый байт — encoding + lang length, парсим вручную
}
}
}
}
func readerSession(_ session: NFCNDEFReaderSession, didInvalidateWithError error: Error) {
// NFCReaderError.readerSessionInvalidationErrorUserCanceled — пользователь закрыл
// NFCReaderError.readerSessionInvalidationErrorSessionTimeout — таймаут
}
} כתיבה לתגים
func readerSession(_ session: NFCNDEFReaderSession, didDetect tags: [NFCNDEFTag]) {
guard let tag = tags.first else { return }
session.connect(to: tag) { error in
guard error == nil else { return }
tag.queryNDEFStatus { status, capacity, error in
guard status == .readWrite else {
session.invalidate(errorMessage: "Тег защищён от записи")
return
}
let payload = NFCNDEFPayload.wellKnownTypeURIPayload(url: URL(string: "https://example.com")!)!
let message = NFCNDEFMessage(records: [payload])
tag.writeNDEF(message) { error in
session.invalidate(errorMessage: error != nil ? "Ошибка записи" : nil)
}
}
}
}עבור תגים לא-NDEF (כרטיסי בנק ISO 7816, דרכונים) יש צורך ב-import CoreNFC class NFCManager: NSObject, NFCNDEFReaderSessionDelegate { var session: NFCNDEFReaderSession? func startReading() { guard NFCNDEFReaderSession.readingAvailable else { // устройство не поддерживает NFC или NFC отключён return } session = NFCNDEFReaderSession(delegate: self, queue: nil, invalidateAfterFirstRead: true) session?.alertMessage = "Поднесите NFC-метку" session?.begin() } func readerSession(_ session: NFCNDEFReaderSession, didDetectNDEFs messages: [NFCNDEFMessage]) { for message in messages { for record in message.records { if record.typeNameFormat == .nfcWellKnown, let type = String(data: record.type, encoding: .utf8), type == "T" { // текстовая запись let payload = record.payload // первый байт — encoding + lang length, парсим вручную } } } } func readerSession(_ session: NFCNDEFReaderSession, didInvalidateWithError error: Error) { // NFCReaderError.readerSessionInvalidationErrorUserCanceled — пользователь закрыл // NFCReaderError.readerSessionInvalidationErrorSessionTimeout — таймаут } } עם func readerSession(_ session: NFCNDEFReaderSession, didDetect tags: [NFCNDEFTag]) { guard let tag = tags.first else { return } session.connect(to: tag) { error in guard error == nil else { return } tag.queryNDEFStatus { status, capacity, error in guard status == .readWrite else { session.invalidate(errorMessage: "Тег защищён от записи") return } let payload = NFCNDEFPayload.wellKnownTypeURIPayload(url: URL(string: "https://example.com")!)! let message = NFCNDEFMessage(records: [payload]) tag.writeNDEF(message) { error in session.invalidate(errorMessage: error != nil ? "Ошибка записи" : nil) } } } } . קריאת דרכונים (ePassport) דורשת PACE או Basic Access Control עם מפתחות ממחרוזת MRZ.
אנדרואיד: NfcAdapter ו-Foreground Dispatch
ממשק ה-API של NFC באנדרואיד פתוח יותר. NFCTagReaderSession בודק NFC. pollingOption: [.iso14443] מיירט תגים בזמן שהאפליקציה בחזית.
val nfcAdapter = NfcAdapter.getDefaultAdapter(context)
// В onResume
val intent = Intent(context, activity.javaClass).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)
val pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_MUTABLE)
nfcAdapter.enableForegroundDispatch(activity, pendingIntent, null, null)
// В onNewIntent
fun handleNfcIntent(intent: Intent) {
val tag = intent.getParcelableExtra<Tag>(NfcAdapter.EXTRA_TAG) ?: return
val ndef = Ndef.get(tag)
if (ndef != null) {
ndef.connect()
val message = ndef.ndefMessage
for (record in message.records) {
val payload = String(record.payload, Charsets.UTF_8)
}
ndef.close()
}
}עבור MIFARE Classic, השתמשו במחלקה NfcAdapter.getDefaultAdapter(context). דורש אימות מפתח לפני קריאת סקטור. מפתח ברירת מחדל A: enableForegroundDispatch. רוב כרטיסי התחבורה משתמשים במפתחות מותאמים אישית. ל-MIFARE Classic 1K יש 16 סקטורים של 4 בלוקים; קריאת סקטור אחד עם אימות אורכת כ-50 אלפיות השנייה.
בעיות אופייניות
פסק זמן של סשן iOS. val nfcAdapter = NfcAdapter.getDefaultAdapter(context) // В onResume val intent = Intent(context, activity.javaClass).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP) val pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_MUTABLE) nfcAdapter.enableForegroundDispatch(activity, pendingIntent, null, null) // В onNewIntent fun handleNfcIntent(intent: Intent) { val tag = intent.getParcelableExtra<Tag>(NfcAdapter.EXTRA_TAG) ?: return val ndef = Ndef.get(tag) if (ndef != null) { ndef.connect() val message = ndef.ndefMessage for (record in message.records) { val payload = String(record.payload, Charsets.UTF_8) } ndef.close() } } חי 60 שניות. אם המשתמש לא מקרב את התג בזמן, הסשן נסגר עם שגיאה. ספקו הוראות ברורות והציעו לנסות שוב.
עימות עם אפליקציות תשלום באנדרואיד. אם Google Pay מותקן ומוגדר כאפליקציית NFC ברירת מחדל, MifareClassic מיירט תגים רק בזמן שהאפליקציה פעילה. ברקע, Google Pay משתלט.
NFC לא עובד עם כיסוי. לא בדיחה — חלק מהכיסויים המתכתיים חוסמים את האנטנה. יש לתאר זאת בדרישות השימוש.
מדוע מתרחש פסק זמן של סשן iOS?
פסק הזמן של 60 שניות מובנה ב-Core NFC כדי למנוע תקיעות. אם האפליקציה לא מעבדת תג בתוך זמן זה, הסשן נסגר אוטומטית. פתרון: הציגו התראה עם כפתור ניסיון חוזר גדול והדגישו את אזור הסריקה.
כיצד להגן על כתיבת תגי NFC מפני שיבוש?
השתמשו בחתימה דיגיטלית לפני כתיבה, או הצפינו רשומות NDEF. מבחינת חומרה, השתמשו בתגים עם גישה מאובטחת (למשל, NTAG 424 DNA). אנו גם מיישמים מפתחות HMAC לאימות שלמות.
השוואת פלטפורמות: iOS CoreNFC מול Android NfcAdapter
iOS CoreNFC מספקת רמת אבטחה גבוהה יותר בהשוואה ל-Android NfcAdapter — ההסתברות ליירוט נתונים מופחתת בחצי בשל סשן סגור ואישור משתמש חובה. עם זאת, אנדרואיד מציעה גמישות רבה יותר: תמיכה ב-MIFARE Classic, פעולת רקע, ואמולציית כרטיסים. לפרויקטים שמעדיפים אבטחה, בחרו ב-iOS; לתאימות מקסימלית, בחרו באנדרואיד.
כיצד אנו פותרים בעיות שילוב NFC
ניתוח דרישות
אנו קובעים סוגי תגים, מצבים (קריאה/כתיבה/אמולציה), וצורך בסריקת רקע. עבור iOS, אנו בודקים אם ניתן להשתמש ב-URL schemes מותאמים אישית.
עיצוב
אנו בוחרים את הארכיטקטורה: עבור NDEF, {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF} פשוט. עבור MIFARE, NFCNDEFReaderSession עם קריאות APDU. באנדרואיד, foreground dispatch בתוספת enableForegroundDispatch לפעולת רקע.
יישום
אנו כותבים קוד. אנו מבטיחים טיפול בשגיאות (פסק זמן סשן, תג לא ניתן לכתיבה). אנו תומכים בפורמטי NDEF שונים: URI, טקסט, Smart Poster.
בדיקות
אנו בודקים על תגים אמיתיים: NTAG213, MIFARE Classic, FeliCa. אנו מדמים פסק זמן. עבור iOS, אנו משתמשים ב-NFC TagInfo לניפוי.
השקה וניטור
אנו מפרסמים דרך TestFlight ו-Google Play Console. אנו מנטרים דוחות קריסה, במיוחד עבור סשני NFC.
מה כלול?
| תוצר | תיאור |
|---|---|
| ניתוח תאימות | בדיקת סוגי תגים וגרסאות מערכת הפעלה |
| תיעוד ארכיטקטוני | דיאגרמת רצף לאינטראקציית NFC |
| קוד שילוב | מודול iOS או אנדרואיד עם לוגיקת קריאה/כתיבה |
| בדיקות עם תגי ייחוס | עד 5 סוגי תגים |
| תמיכה לאחר השקה | חודש אחריות על באגים קריטיים |
ציר זמן
| משימה | זמן |
|---|---|
| קריאת NDEF (פלטפורמה אחת) | מיומיים |
| כתיבת NDEF + לא-NDEF (iOS+אנדרואיד) | מ-5 ימים |
| עבודה עם MIFARE או ePassport | מ-8 ימים |
התמחור נקבע באופן אישי לאחר סקירת הפרויקט. צרו קשר — נבחן את המשימה שלכם תוך יום אחד. קבלו ייעוץ על שילוב NFC.
למה לבחור בנו?
- 10+ שנים בפיתוח מובייל.
- העברנו בהצלחה 20+ פרויקטי NFC.
- אחריות לעמידה ב-הנחיות סקירת App Store (סעיף 4.2/5.1) ו-Google Play.
- מספקים אישורי תאימות לתגים לפי בקשה.
צרו קשר כדי להעריך את הפרויקט שלכם. ניסיון עם Apple Wallet, Google Pay, ואסימונים מותאמים אישית.







