Core NFC框架詳細(xì)解析 (二) —— CoreNFC使用簡單示例(一)

版本號(hào) 時(shí)間
V1.0 2020.06.07 星期日

前言

今天翻閱蘋果的API文檔,發(fā)現(xiàn)多了一個(gè)框架Core NFC,看了下才看見是iOS11.0新添加的框架,這里我們就一起來看一下框架Core NFC。感興趣的看下面幾篇文章。
1. Core NFC框架詳細(xì)解析 (一) —— 基本概覽(一)

開始

首先看下主要內(nèi)容:

在本教程中,您將學(xué)習(xí)如何使用CoreNFC無線連接到其他設(shè)備或NFC標(biāo)簽。內(nèi)容來自翻譯。

下面看下寫作環(huán)境:

Swift 5, iOS 13, Xcode 11

Near Field Communication(NFC)是一種用于短距離無線設(shè)備與其他設(shè)備共享數(shù)據(jù)或觸發(fā)這些設(shè)備上的動(dòng)作的技術(shù)。它使用射頻場(chǎng)(radio frequency field)進(jìn)行構(gòu)建,它可以使沒有電源的設(shè)備存儲(chǔ)小塊數(shù)據(jù),同時(shí)還使其他有源設(shè)備可以讀取該數(shù)據(jù)。

iOSwatchOS設(shè)備已經(jīng)內(nèi)置了NFC硬件已有幾年了。實(shí)際上,Apple Pay使用此技術(shù)與商店中的支付終端進(jìn)行交互。但是,開發(fā)人員要到iOS 11才能使用NFC硬件。

蘋果通過引入Core NFC提升了iOS 13中的NFC游戲。借助這項(xiàng)新技術(shù),您可以對(duì)iOS設(shè)備進(jìn)行編程,使其以新方式與周圍的互聯(lián)世界互動(dòng)。本教程將向您展示一些使用該技術(shù)的方法。在此過程中,您將學(xué)習(xí)如何:

  • 將標(biāo)準(zhǔn)信息寫入NFC tag標(biāo)簽。
  • 閱讀該信息。
  • 將自定義信息保存到標(biāo)簽tag。
  • 修改標(biāo)簽上已經(jīng)找到的數(shù)據(jù)。

重要說明:要執(zhí)行本教程中的所有步驟,您需要滿足以下條件:

  • 物理iOS設(shè)備
  • 蘋果開發(fā)者帳戶
  • 您可以讀取和寫入的NFC硬件。許多在線零售商都以合理的價(jià)格攜帶NFC tag。通常,您可以以大約10美元的價(jià)格獲得一包NFC標(biāo)簽。在說明中尋找表明它是可編程的或列出其存儲(chǔ)容量(通常為300500字節(jié))的內(nèi)容。具有該近似容量的任何設(shè)備都超出了本教程的范圍。

starter文件夾中打開starter項(xiàng)目。 使用項(xiàng)目應(yīng)用程序,您將學(xué)習(xí)如何:

  • NFC tag設(shè)置為“l(fā)ocation”。
  • 掃描location tag以查看其名稱和訪客日志。
  • 將訪問者(visitor)添加到位置標(biāo)簽(location tag)。

構(gòu)建并運(yùn)行。 您會(huì)看到以下內(nèi)容:


Writing to Your First Tag

首先,在Project navigator中選擇NeatoCache項(xiàng)目。 然后,轉(zhuǎn)到Signing & Capability,然后選擇+ Capability。 從列表中選擇Near Field Communication Tag Reading。

這將確保您的應(yīng)用程序的配置文件(provisioning profile)設(shè)置為使用NFC

接下來,打開您的Info.plist并添加以下條目:

  • KeyPrivacy – NFC Scan Usage Description
  • Value:使用NFC讀取和寫入數(shù)據(jù)

您需要此條目來向用戶傳達(dá)您正在使用NFC功能的用途,并符合Apple關(guān)于在應(yīng)用程序中使用NFC的要求。

接下來,您將添加一個(gè)函數(shù),該函數(shù)可以執(zhí)行您的應(yīng)用將處理的各種NFC任務(wù)。 打開NFCUtility.swift并將以下導(dǎo)入和類型別名添加到文件頂部:

import CoreNFC

typealias NFCReadingCompletion = (Result<NFCNDEFMessage?, Error>) -> Void
typealias LocationReadingCompletion = (Result<Location, Error>) -> Void

您需要導(dǎo)入CoreNFC才能使用NFC。 類型別名(type aliases)提供以下功能:

  • NFCReadingCompletion用于完成通用標(biāo)簽讀取任務(wù)。
  • LocationReadingCompletion,用于讀取配置為位置的標(biāo)簽

接下來,將以下屬性和方法添加到NFCUtility

// 1
private var session: NFCNDEFReaderSession?
private var completion: LocationReadingCompletion?

// 2
static func performAction(
  _ action: NFCAction,
  completion: LocationReadingCompletion? = nil
) {
  // 3
  guard NFCNDEFReaderSession.readingAvailable else {
    completion?(.failure(NFCError.unavailable))
    print("NFC is not available on this device")
    return
  }

  shared.action = action
  shared.completion = completion
  // 4
  shared.session = NFCNDEFReaderSession(
    delegate: shared.self,
    queue: nil,
    invalidateAfterFirstRead: false)
  // 5
  shared.session?.alertMessage = action.alertMessage
  // 6
  shared.session?.begin()
}

如果您由于不符合NFCNDEFReaderSessionDelegate而此時(shí)遇到編譯錯(cuò)誤,請(qǐng)不要擔(dān)心,您將立即修復(fù)此問題。

這是您剛剛做的:

  • 1) 您添加sessioncompletion屬性以存儲(chǔ)活動(dòng)的NFC reading session及其完成塊(completion block)。
  • 2) 添加靜態(tài)函數(shù)作為NFC讀寫任務(wù)的入口點(diǎn)。通常,您將使用單例樣式訪問此函數(shù)和NFCUtility
  • 3) 確保設(shè)備支持NFC讀取。否則,請(qǐng)返回errorcomplete。
  • 4) 創(chuàng)建一個(gè)NFCNDEFReaderSession,它代表活動(dòng)的閱讀會(huì)話。您還可以設(shè)置代表以通知NFC閱讀會(huì)話的各種事件。
  • 5) 您可以在會(huì)話上設(shè)置alertMessage屬性,以使其在NFC模式下向用戶顯示該文本。
  • 6) 開始閱讀會(huì)話。調(diào)用時(shí),模態(tài)將向用戶呈現(xiàn)您在上一步中設(shè)置的所有指令。

1. Understanding NDEF

請(qǐng)注意,上面的代碼引入了另一個(gè)首字母縮寫詞NDEF,代表NFC Data Exchange Format。這是用于寫入或讀取NFC設(shè)備的標(biāo)準(zhǔn)格式。您將使用兩種NDEF:

  • NDEF Record:其中包含您的有效載荷(payload)值,例如字符串,URL或自定義數(shù)據(jù)。它還包含有關(guān)該有效負(fù)載值的信息,例如長度和類型。此信息是CoreNFC中的NFCNDEFPayload
  • NDEF Message:這是保存NDEF記錄的數(shù)據(jù)結(jié)構(gòu)。 NDEF消息中可以有一個(gè)或多個(gè)NDEF記錄。

2. Detecting Tags

現(xiàn)在,您已經(jīng)設(shè)置了NFCReaderSession,現(xiàn)在遵循NFCUtility成為代理了,這樣就可以通知您在讀取會(huì)話期間發(fā)生的各種事件。

將以下代碼添加到NFCUtility.swift的底部:

// MARK: - NFC NDEF Reader Session Delegate
extension NFCUtility: NFCNDEFReaderSessionDelegate {
  func readerSession(
    _ session: NFCNDEFReaderSession,
    didDetectNDEFs messages: [NFCNDEFMessage]
  ) {
    // Not used
  }
}

您將在一秒鐘內(nèi)向此擴(kuò)展添加更多內(nèi)容,但請(qǐng)注意,在本教程中,您將不會(huì)對(duì)readerSession(_:didDetectNDEFs :)進(jìn)行任何操作。 您僅在此處添加它,因?yàn)楸仨氉袷匚袇f(xié)議。

NFC技術(shù)的互動(dòng)越多,您越會(huì)發(fā)現(xiàn)在讀寫過程的各個(gè)階段遇到錯(cuò)誤的可能性。 將以下方法添加到新擴(kuò)展中以捕獲這些錯(cuò)誤:

private func handleError(_ error: Error) {
  session?.alertMessage = error.localizedDescription
  session?.invalidate()
}

代碼的第一行應(yīng)該看起來很熟悉。 它將在NFC模式視圖中向用戶顯示錯(cuò)誤消息。 如果發(fā)生錯(cuò)誤,您還將使會(huì)話無效以終止會(huì)話并允許用戶再次與該應(yīng)用進(jìn)行交互。

接下來,將以下方法添加到擴(kuò)展中以處理NFC讀取會(huì)話中的錯(cuò)誤:

func readerSession(
  _ session: NFCNDEFReaderSession,
  didInvalidateWithError error: Error
) {
  if let error = error as? NFCReaderError,
    error.code != .readerSessionInvalidationErrorFirstNDEFTagRead &&
      error.code != .readerSessionInvalidationErrorUserCanceled {
    completion?(.failure(NFCError.invalidated(message: 
      error.localizedDescription)))
  }

  self.session = nil
  completion = nil
}

添加此委托方法將清除到目前為止您遇到的所有編譯錯(cuò)誤。

最后,將最后一種方法添加到您的擴(kuò)展中,以處理可能的NFC標(biāo)簽檢測(cè):

func readerSession(
  _ session: NFCNDEFReaderSession,
  didDetect tags: [NFCNDEFTag]
) {
  guard 
    let tag = tags.first,
    tags.count == 1 
    else {
      session.alertMessage = """
        There are too many tags present. Remove all and then try again.
        """
      DispatchQueue.global().asyncAfter(deadline: .now() + .milliseconds(500)) {
        session.restartPolling()
      }
      return
  }
}

在這里,您可以實(shí)現(xiàn)在會(huì)話檢測(cè)到您掃描標(biāo)簽時(shí)將調(diào)用的方法。

通常,您希望用戶只有一個(gè)標(biāo)簽離手機(jī)足夠近,但是您應(yīng)該考慮多個(gè)標(biāo)簽。 如果檢測(cè)到此情況,則將停止掃描并alert給用戶。 顯示該消息后,您將重新啟動(dòng)閱讀會(huì)話,并讓您的用戶再試一次。

3. Handling the Tag

知道有一個(gè)標(biāo)簽后,您可能想對(duì)它做些事情。 在readerSession(_:didDetect :)中的guard聲明之后添加以下代碼:

// 1
session.connect(to: tag) { error in
  if let error = error {
    self.handleError(error)
    return
  }

  // 2
  tag.queryNDEFStatus { status, _, error in
    if let error = error {
      self.handleError(error)
      return
    }

    // 3
    switch (status, self.action) {
    case (.notSupported, _):
      session.alertMessage = "Unsupported tag."
      session.invalidate()
    case (.readOnly, _):
      session.alertMessage = "Unable to write to tag."
      session.invalidate()
    case (.readWrite, .setupLocation(let locationName)):
      self.createLocation(name: locationName, with: tag)
    case (.readWrite, .readLocation):
      return
    default:
      return
    }
  }
}

您在上面的代碼中正在做的事情是:

  • 1) 使用當(dāng)前的NCFNDEFReaderSession連接到檢測(cè)到的標(biāo)簽。您需要執(zhí)行此步驟以執(zhí)行對(duì)標(biāo)簽的任何讀取或?qū)懭?。連接后,它將調(diào)用其完成處理程序,并可能發(fā)生任何錯(cuò)誤。
  • 2) 在標(biāo)簽中查詢其NDEF狀態(tài),以查看是否支持NFC設(shè)備。就您的NeatoCache應(yīng)用而言,狀態(tài)必須為readWrite。
  • 3) 切換狀態(tài)和NFC操作,并根據(jù)其值確定應(yīng)執(zhí)行的操作。在這里,您嘗試使用createLocation(name:with :)將標(biāo)簽設(shè)置為具有位置名稱,該名稱尚不存在,因此會(huì)遇到編譯錯(cuò)誤。不用擔(dān)心,您稍后會(huì)添加它。同樣,readLocation操作也尚未處理。

4. Creating the Payload

到目前為止,您已經(jīng)在尋找標(biāo)簽,連接標(biāo)簽并查詢其狀態(tài)。要完成對(duì)標(biāo)簽的寫入設(shè)置,請(qǐng)?jiān)?code>NFCUtility.swift的末尾添加以下代碼塊:

// MARK: - Utilities
extension NFCUtility {
  func createLocation(name: String, with tag: NFCNDEFTag) {
    // 1
    guard let payload = NFCNDEFPayload
      .wellKnownTypeTextPayload(string: name, locale: Locale.current) 
      else {
        handleError(NFCError.invalidated(message: "Could not create payload"))
        return
    }

    // 2
    let message = NFCNDEFMessage(records: [payload])

    // 3
    tag.writeNDEF(message) { error in
      if let error = error {
        self.handleError(error)
        return
      }

      self.session?.alertMessage = "Wrote location data."
      self.session?.invalidate()
      self.completion?(.success(Location(name: name)))
    }
  }
}

您在上面的代碼中正在做的事情是:

  • 1) 創(chuàng)建文本NFCNDEFPayload。如前所述,這類似于NDEF記錄。
  • 2) 使用有效負(fù)載創(chuàng)建新的NFCNDEFMessage,以便可以將其保存到NFC設(shè)備。
  • 3) 最后,將消息寫入標(biāo)簽。

5. Using NDEF Payload Types

NFCNDEFPayload支持幾種不同類型的數(shù)據(jù)。在此示例中,您使用的是wellKnownTypeTextPayload(string:locale :)。這是一種非常簡單的數(shù)據(jù)類型,它使用字符串和設(shè)備的當(dāng)前語言環(huán)境。其他一些數(shù)據(jù)類型包含更復(fù)雜的信息。完整清單如下:

  • Empty
  • Well-Known
  • MIME media-type
  • Absolute URI
  • External
  • Unknown
  • Unchanged
  • Reserved

注意:本教程涵蓋了Well-KnownUnknown。要了解其他類型,請(qǐng)查看本教程末尾列出的鏈接。

另請(qǐng)注意,類型可以具有子類型。例如,Well-known的具有TextURI的子類型。

您真的很接近!剩下的就是將用戶界面連接到新代碼。轉(zhuǎn)到AdminView.swift并替換以下代碼:

Button(action: {
}) {
  Text("Save Location…")
}
.disabled(locationName.isEmpty)

使用

Button(action: {
  NFCUtility.performAction(.setupLocation(locationName: self.locationName)) { _ in
    self.locationName = ""
  }
}) {
  Text("Save Location…")
}
.disabled(locationName.isEmpty)

這將進(jìn)行調(diào)用,以使用在text field中找到的文本來設(shè)置您的位置。

構(gòu)建并運(yùn)行,切換到應(yīng)用程序的Admin選項(xiàng)卡,輸入名稱并選擇Save Location…。

您會(huì)看到以下內(nèi)容:

注意:請(qǐng)記住,您需要使用物理設(shè)備并具有支持寫入功能的NFC標(biāo)簽。

將手機(jī)放在NFC標(biāo)簽上后,您會(huì)看到一條消息,說明您的位置已成功保存。

6. Reading the Tag

很好! 現(xiàn)在,您已經(jīng)有了一個(gè)可以在標(biāo)簽中寫入字符串的應(yīng)用程序,您就可以為讀取標(biāo)簽提供支持。 返回NFCUtility.swift并在readerSession(_:didDetect :)中找到以下代碼。

case (.readWrite, .readLocation):
  return

現(xiàn)在,替換它使用下面:

case (.readWrite, .readLocation):
  self.readLocation(from: tag)

是時(shí)候?qū)崿F(xiàn)該readLocation(from :)方法了。 將以下內(nèi)容添加到包含createLocation(name:with :)Utilities擴(kuò)展中:

func readLocation(from tag: NFCNDEFTag) {
  // 1
  tag.readNDEF { message, error in
    if let error = error {
      self.handleError(error)
      return
    }
    // 2
    guard 
      let message = message,
      let location = Location(message: message) 
      else {
        self.session?.alertMessage = "Could not read tag data."
        self.session?.invalidate()
        return
    }
    self.completion?(.success(location))
    self.session?.alertMessage = "Read tag."
    self.session?.invalidate()
  }
}

您對(duì)添加的內(nèi)容應(yīng)該有點(diǎn)熟悉,因?yàn)樗c您寫入標(biāo)簽的方式非常相似。

  • 1) 首先,您開始讀取標(biāo)簽。 如果可以讀取,它將返回找到的所有消息。
  • 2) 接下來,如果有,嘗試從消息數(shù)據(jù)中創(chuàng)建一個(gè)Location。 這使用了一個(gè)接受NFCNDEFMessage并將其命名的自定義初始化程序。 如果您感到好奇,可以在LocationModel.swift中找到該初始化程序。

最后,打開VisitorView.swift,并在scanSection中,替換以下代碼:

Button(action: {
}) {
  Text("Scan Location Tag…")
}

使用下面

Button(action: {
  NFCUtility.performAction(.readLocation) { location in
    self.locationModel = try? location.get()
  }
}) {
  Text("Scan Location Tag…")
}

您已經(jīng)準(zhǔn)備好從標(biāo)簽中讀取數(shù)據(jù)。 構(gòu)建并運(yùn)行。

Visitors選項(xiàng)卡上,點(diǎn)擊Scan Location Tag…。 您會(huì)在用戶界面中看到以下內(nèi)容以及您的位置名稱:


Writing Different Data Types

盡管在某些情況下寫字符串可能會(huì)完美地工作,但您可能會(huì)發(fā)現(xiàn)想要將其他類型的數(shù)據(jù)寫到標(biāo)簽中。

為此,請(qǐng)?jiān)?code>Utilities擴(kuò)展中的NFCUtility.swift中添加以下內(nèi)容:

private func read(
  tag: NFCNDEFTag,
  alertMessage: String = "Tag Read",
  readCompletion: NFCReadingCompletion? = nil
) {
  tag.readNDEF { message, error in
    if let error = error {
      self.handleError(error)
      return
    }

    // 1
    if let readCompletion = readCompletion,
       let message = message {
      readCompletion(.success(message))
    } else if 
      let message = message,
      let record = message.records.first,
      let location = try? JSONDecoder()
        .decode(Location.self, from: record.payload) {
      // 2
      self.completion?(.success(location))
      self.session?.alertMessage = alertMessage
      self.session?.invalidate()
    } else {
      self.session?.alertMessage = "Could not decode tag data."
      self.session?.invalidate()
    }
  }
}

從現(xiàn)在開始,這種讀取標(biāo)簽的新方法將成為您大多數(shù)活動(dòng)的切入點(diǎn)。 如您所見,它仍然像以前一樣讀取標(biāo)簽。 但是,一旦讀取標(biāo)簽,它將執(zhí)行以下兩項(xiàng)操作之一:

  • 1) 調(diào)用completion handler并將消息傳遞給它。 這對(duì)于將多個(gè)NFC任務(wù)鏈接在一起非常有用。
  • 2) 解碼有效負(fù)載(payload),以便您可以解析標(biāo)簽的記錄。 您將稍后再講到這一點(diǎn)。

1. Writing Custom Data Instead of Strings

此時(shí),您已經(jīng)準(zhǔn)備好將應(yīng)用程序從編寫字符串到標(biāo)簽轉(zhuǎn)換為將自定義數(shù)據(jù)寫入標(biāo)簽。 將以下內(nèi)容添加到Utilities擴(kuò)展中:

private func createLocation(_ location: Location, tag: NFCNDEFTag) {
  read(tag: tag) { _ in
    self.updateLocation(location, tag: tag)
  }
}

這是用于創(chuàng)建帶有位置標(biāo)簽的新函數(shù)。 您可以看到它使用新的read(tag:alsertMessage:readCompletion :)啟動(dòng)該過程,并調(diào)用了一個(gè)新函數(shù)來更新標(biāo)簽上的位置,還調(diào)用了一個(gè)新的暫時(shí)實(shí)施updateLocation(_:tag :)方法。

由于您要替換將位置信息寫入標(biāo)簽的方式,因此請(qǐng)刪除NFCUtility擴(kuò)展程序開頭的createLocation(name:with :),因?yàn)椴辉傩枰?另外,從以下代碼在readerSession(_:didDetect :)中更新代碼:

case (.readWrite, .setupLocation(let locationName)):
  self.createLocation(name: locationName, with: tag)

到下面

case (.readWrite, .setupLocation(let locationName)):
  self.createLocation(Location(name: locationName), tag: tag)

createLocation(_:tag:)后面添加這個(gè)方法:

private func updateLocation(
  _ location: Location,
  withVisitor visitor: Visitor? = nil,
  tag: NFCNDEFTag
) {
  // 1
  var alertMessage = "Successfully setup location."
  var tempLocation = location
  
  // 2
  let jsonEncoder = JSONEncoder()
  guard let customData = try? jsonEncoder.encode(tempLocation) else {
    self.handleError(NFCError.invalidated(message: "Bad data"))
    return
  }
  // 3
  let payload = NFCNDEFPayload(
    format: .unknown,
    type: Data(),
    identifier: Data(),
    payload: customData)
  // 4
  let message = NFCNDEFMessage(records: [payload])
}

您在上面的代碼中正在做的事情是:

  • 1) 創(chuàng)建默認(rèn)alert消息和臨時(shí)位置。 稍后您將回到這些內(nèi)容。
  • 2) 對(duì)傳遞給函數(shù)的Location結(jié)構(gòu)進(jìn)行編碼。 這會(huì)將模型轉(zhuǎn)換為原始數(shù)據(jù)(Data)。 這很重要,因?yàn)檫@是將任何自定義類型寫入NFC標(biāo)簽的方式。
  • 3) 創(chuàng)建可以處理數(shù)據(jù)的有效負(fù)載(payload)。 但是,您現(xiàn)在使用unknown作為格式。 這樣做時(shí),必須將typeidentifier設(shè)置為空數(shù)據(jù)Data,而有效負(fù)載(payload)參數(shù)將承載實(shí)際的解碼模型。
  • 4) 將有效負(fù)載添加到新創(chuàng)建的消息中。

總體而言,這似乎與將字符串保存到標(biāo)簽中時(shí)沒什么不同,只是增加了一個(gè)步驟,將Swift數(shù)據(jù)類型轉(zhuǎn)換為標(biāo)簽可理解的內(nèi)容。

2. Checking Tag Capacity

要完成將數(shù)據(jù)寫入標(biāo)簽,請(qǐng)?jiān)?code>updateLocation(_:withVisitor:tag)中添加下一個(gè)代碼塊:

tag.queryNDEFStatus { _, capacity, _ in
  // 1
  guard message.length <= capacity else {
    self.handleError(NFCError.invalidPayloadSize)
    return
  }

  // 2
  tag.writeNDEF(message) { error in
    if let error = error {
      self.handleError(error)
      return
    }
    
    if self.completion != nil {
      self.read(tag: tag, alertMessage: alertMessage)
    }
  }
}

上面的閉包嘗試查詢當(dāng)前NDEF狀態(tài),然后:

  • 1) 確保設(shè)備有足夠的存儲(chǔ)空間來存儲(chǔ)位置。 請(qǐng)記住,與您可能熟悉的設(shè)備相比,NFC標(biāo)簽通常具有極其有限的存儲(chǔ)容量。
  • 2) 將消息寫入標(biāo)簽。

與上面一樣,構(gòu)建并運(yùn)行并設(shè)置位置。 如果愿意,可以使用之前的相同標(biāo)簽,因?yàn)樾麓a將覆蓋以前保存的所有數(shù)據(jù)。

3. Reading Your Custom Data

此時(shí),如果您嘗試讀取標(biāo)簽,將會(huì)收到錯(cuò)誤消息。 保存的數(shù)據(jù)不再是眾所周知的類型。 要解決此問題,請(qǐng)?jiān)?code>readerSession(_:didDetect :)中替換以下代碼:

case (.readWrite, .readLocation):
  self.readLocation(from: tag)

使用

case (.readWrite, .readLocation):
  self.read(tag: tag)

構(gòu)建并運(yùn)行并掃描標(biāo)簽。 因?yàn)槟跊]有任何completion塊的情況下調(diào)用read(tag:alertMessage:readCompletion :),所以它將解碼消息的第一條記錄中找到的數(shù)據(jù)。


Modifying Content

此應(yīng)用程序的最后一項(xiàng)要求是保存訪問此位置的人員的日志。 您的應(yīng)用具有UI中已經(jīng)存在的未使用功能,該功能允許用戶輸入其名稱并將其添加到標(biāo)簽中。 到目前為止,您所做的工作將使其余的設(shè)置變得微不足道。 您已經(jīng)可以將數(shù)據(jù)讀取和寫入標(biāo)簽,因此對(duì)其進(jìn)行修改應(yīng)該很容易。

在創(chuàng)建tempLocation之后,在NFCUtility.swift中,將此代碼添加到updateLocation(_:withVisitor:tag :)

if let visitor = visitor {
  tempLocation.visitors.append(visitor)
  alertMessage = "Successfully added visitor."
}

在上面的代碼中,您檢查是否提供了visitor。 如果是這樣,則將其添加到該位置的Visitors數(shù)組中。

接下來,將以下方法添加到Utilities擴(kuò)展中:

private func addVisitor(_ visitor: Visitor, tag: NFCNDEFTag) {
  read(tag: tag) { message in
    guard 
      let message = try? message.get(),
      let record = message.records.first,
      let location = try? JSONDecoder()
        .decode(Location.self, from: record.payload) 
      else {
        return
    }

    self.updateLocation(location, withVisitor: visitor, tag: tag)
  }
}

這個(gè)新方法將讀取一個(gè)標(biāo)簽,從中獲取消息,并嘗試對(duì)標(biāo)簽上的Location進(jìn)行解碼。

接下來,在readerSession(_:didDetect :)中,向switch語句添加新的case

case (.readWrite, .addVisitor(let visitorName)):
  self.addVisitor(Visitor(name: visitorName), tag: tag)

如果用戶明確想要添加visitor,則將調(diào)用在上一步中添加的函數(shù)。

剩下的就是更新VisitorView.swift。 在visitorSection中,替換以下代碼:

Button(action: {
}) {
  Text("Add To Tag…")
}
.disabled(visitorName.isEmpty)

使用

Button(action: {
  NFCUtility
    .performAction(.addVisitor(visitorName: self.visitorName)) { location in
      self.locationModel = try? location.get()
      self.visitorName = ""
    }
}) {
  Text("Add To Tag…")
}
.disabled(visitorName.isEmpty)

Build并運(yùn)行,然后轉(zhuǎn)到Visitors選項(xiàng)卡。 輸入您的姓名,然后選擇Add To Tag…。 掃描后,您將看到更新的位置以及在標(biāo)記上找到的訪問者列表。

現(xiàn)在,您應(yīng)該熟悉Core NFC的基礎(chǔ)知識(shí)。 框架中還有很多事情沒有在本教程中提到。 例如,您可以添加標(biāo)簽的背景閱讀,這可以為用戶提供一種無需打開應(yīng)用即可與您的應(yīng)用進(jìn)行交互的方式。 如果您使用Apple的Shortcuts應(yīng)用程序來自動(dòng)化您的智能家居設(shè)備,這對(duì)您來說應(yīng)該很熟悉。 您可以在此處找到有關(guān)此操作的更多信息:Adding Support for Background Tag Reading。

要了解更多信息,請(qǐng)查看以下一些重要資源:

Apple's Core NFC Documentation是NFC規(guī)范中Apple支持的所有內(nèi)容的首選資源。

NFC Forum Homepage是放置有關(guān)NFC所需的所有一般信息及其定義的規(guī)范的地方。

后記

本篇主要講述了CoreNFC使用簡單示例,感興趣的給個(gè)贊或者關(guān)注~~~

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容