diff --git a/CoreNFCSampler/ContentView.swift b/CoreNFCSampler/ContentView.swift index 7a27cc2..3e50739 100644 --- a/CoreNFCSampler/ContentView.swift +++ b/CoreNFCSampler/ContentView.swift @@ -9,61 +9,61 @@ import SwiftUI struct ContentView: View { - @StateObject private var reader = NFCTagReader() - @FocusState private var textFieldIsFocused: Bool - - var body: some View { - VStack(spacing: 0) { - Text("Scan Result") - .font(.largeTitle) - Text(reader.readMessage ?? "") - Spacer() - if reader.sessionType == .write { - VStack(alignment: .leading) { - Text("Write Message") - TextField( - "Enter the message.", - text: $reader.writeMesage - ) - .focused($textFieldIsFocused) - .textFieldStyle(RoundedBorderTextFieldStyle()) - } - .padding() - } - if reader.nfcFormat == .ndef { - Picker("Session Type", selection: $reader.sessionType) { - ForEach(SessionType.allCases) { session in - Text(session.rawValue).tag(session) - } - } - .colorMultiply(.accentColor) - .pickerStyle(.segmented) - .padding() - } - Picker("NFC Format", selection: $reader.nfcFormat) { - ForEach(NFCFormat.allCases) { session in - Text(session.rawValue).tag(session) - } - } - .colorMultiply(.accentColor) - .pickerStyle(.segmented) - .padding() - Button(action: { - reader.beginScanning() - }, label: { - Text("Scan") - .frame(width: 200, height: 15) - }) - .padding() - .accentColor(Color.white) - .background(Color.accentColor) - .cornerRadius(.infinity) - .disabled(!reader.readingAvailable) + @StateObject private var reader = NFCTagReader() + @FocusState private var textFieldIsFocused: Bool + + var body: some View { + VStack(spacing: 0) { + Text("Scan Result") + .font(.largeTitle) + Text(reader.readMessage ?? "") + Spacer() + if reader.sessionType == .write { + VStack(alignment: .leading) { + Text("Write Message") + TextField( + "Enter the message.", + text: $reader.writeMesage + ) + .focused($textFieldIsFocused) + .textFieldStyle(RoundedBorderTextFieldStyle()) } .padding() + } + if reader.nfcFormat == .ndef { + Picker("Session Type", selection: $reader.sessionType) { + ForEach(SessionType.allCases) { session in + Text(session.rawValue).tag(session) + } + } + .colorMultiply(.accentColor) + .pickerStyle(.segmented) + .padding() + } + Picker("NFC Format", selection: $reader.nfcFormat) { + ForEach(NFCFormat.allCases) { session in + Text(session.rawValue).tag(session) + } + } + .colorMultiply(.accentColor) + .pickerStyle(.segmented) + .padding() + Button(action: { + reader.beginScanning() + }, label: { + Text("Scan") + .frame(width: 200, height: 15) + }) + .padding() + .accentColor(Color.white) + .background(Color.accentColor) + .cornerRadius(.infinity) + .disabled(!reader.readingAvailable) } + .padding() + } } #Preview { - ContentView() + ContentView() } diff --git a/CoreNFCSampler/CoreNFCSamplerApp.swift b/CoreNFCSampler/CoreNFCSamplerApp.swift index 733a707..2c726d7 100644 --- a/CoreNFCSampler/CoreNFCSamplerApp.swift +++ b/CoreNFCSampler/CoreNFCSamplerApp.swift @@ -10,9 +10,9 @@ import SwiftUI @main struct CoreNFCSamplerApp: App { - var body: some Scene { - WindowGroup { - ContentView() - } + var body: some Scene { + WindowGroup { + ContentView() } + } } diff --git a/CoreNFCSampler/NFCTagReader.swift b/CoreNFCSampler/NFCTagReader.swift index fbefc47..ae2c09d 100644 --- a/CoreNFCSampler/NFCTagReader.swift +++ b/CoreNFCSampler/NFCTagReader.swift @@ -9,180 +9,180 @@ import CoreNFC final class NFCTagReader: NSObject, ObservableObject { - private var session: NFCNDEFReaderSession? - private var tagSession: NFCTagReaderSession? - - var writeMesage = "CoreNFCTest" - let readingAvailable: Bool - - @Published var sessionType = SessionType.read - @Published var nfcFormat = NFCFormat.ndef - @Published var readMessage: String? - - override init() { - readingAvailable = NFCNDEFReaderSession.readingAvailable + private var session: NFCNDEFReaderSession? + private var tagSession: NFCTagReaderSession? + + var writeMesage = "CoreNFCTest" + let readingAvailable: Bool + + @Published var sessionType = SessionType.read + @Published var nfcFormat = NFCFormat.ndef + @Published var readMessage: String? + + override init() { + readingAvailable = NFCNDEFReaderSession.readingAvailable + } + + func beginScanning() { + guard readingAvailable else { + print("This iPhone is not NFC-enabled.") + return } - func beginScanning() { - guard readingAvailable else { - print("This iPhone is not NFC-enabled.") - return - } - - switch nfcFormat { - case .ndef: - session = NFCNDEFReaderSession(delegate: self, queue: nil, invalidateAfterFirstRead: false) - session?.alertMessage = "Please bring your iPhone close to the NFC tag." - session?.begin() - - case .suica: - tagSession = NFCTagReaderSession(pollingOption: .iso18092, delegate: self, queue: nil) - tagSession?.alertMessage = "Please bring your iPhone close to the NFC tag." - tagSession?.begin() - } + switch nfcFormat { + case .ndef: + session = NFCNDEFReaderSession(delegate: self, queue: nil, invalidateAfterFirstRead: false) + session?.alertMessage = "Please bring your iPhone close to the NFC tag." + session?.begin() + + case .suica: + tagSession = NFCTagReaderSession(pollingOption: .iso18092, delegate: self, queue: nil) + tagSession?.alertMessage = "Please bring your iPhone close to the NFC tag." + tagSession?.begin() } - - private func read(tag: NFCNDEFTag, session: NFCNDEFReaderSession) { - tag.readNDEF { [weak self] message, error in - session.alertMessage = "The tag reading has been completed." - session.invalidate() - if let message { - DispatchQueue.main.async { - self?.readMessage = self?.getStringFromNFCNDEF(message: message) - } - } + } + + private func read(tag: NFCNDEFTag, session: NFCNDEFReaderSession) { + tag.readNDEF { [weak self] message, error in + session.alertMessage = "The tag reading has been completed." + session.invalidate() + if let message { + DispatchQueue.main.async { + self?.readMessage = self?.getStringFromNFCNDEF(message: message) } + } } - - private func getStringFromNFCNDEF(message: NFCNDEFMessage) -> String { - message.records.compactMap { - switch $0.typeNameFormat { - case .nfcWellKnown: - if let url = $0.wellKnownTypeURIPayload() { - return url.absoluteString - } - if let text = String(data: $0.payload, encoding: .utf8) { - return text - } - return nil - default: - return nil - } - }.joined(separator: "\n\n") - } + } + + private func getStringFromNFCNDEF(message: NFCNDEFMessage) -> String { + message.records.compactMap { + switch $0.typeNameFormat { + case .nfcWellKnown: + if let url = $0.wellKnownTypeURIPayload() { + return url.absoluteString + } + if let text = String(data: $0.payload, encoding: .utf8) { + return text + } + return nil + default: + return nil + } + }.joined(separator: "\n\n") + } } extension NFCTagReader: NFCNDEFReaderSessionDelegate { - func readerSessionDidBecomeActive(_ session: NFCNDEFReaderSession) { - print("Reader session is active.") - } + func readerSessionDidBecomeActive(_ session: NFCNDEFReaderSession) { + print("Reader session is active.") + } + + func readerSession(_ session: NFCNDEFReaderSession, didInvalidateWithError error: Error) { + print("error:\(error.localizedDescription)") + } + + /// readerSession(_:didDetect:)を実装すると呼び出されなくなる + func readerSession(_ session: NFCNDEFReaderSession, didDetectNDEFs messages: [NFCNDEFMessage]) { + guard messages.count > 0 else { return } - func readerSession(_ session: NFCNDEFReaderSession, didInvalidateWithError error: Error) { - print("error:\(error.localizedDescription)") - } + self.readMessage = getStringFromNFCNDEF(message: messages.first!) + session.alertMessage = "The tag reading has been completed." + session.invalidate() + } + + func readerSession(_ session: NFCNDEFReaderSession, didDetect tags: [NFCNDEFTag]) { + guard tags.count < 2 else { return } - /// readerSession(_:didDetect:)を実装すると呼び出されなくなる - func readerSession(_ session: NFCNDEFReaderSession, didDetectNDEFs messages: [NFCNDEFMessage]) { - guard messages.count > 0 else { return } + let tag = tags.first! + session.connect(to: tag, completionHandler: { (error: Error?) in + guard error == nil else { + session.invalidate(errorMessage: "Unable to connect to tag.") + return + } + + tag.queryNDEFStatus(completionHandler: { [weak self] (ndefStatus: NFCNDEFStatus, capacity: Int, error: Error?) in + guard let self else { return } - self.readMessage = getStringFromNFCNDEF(message: messages.first!) - session.alertMessage = "The tag reading has been completed." - session.invalidate() - } - - func readerSession(_ session: NFCNDEFReaderSession, didDetect tags: [NFCNDEFTag]) { - guard tags.count < 2 else { return } + guard error == nil else { + session.invalidate(errorMessage: "Unable to query the NDEF status of tag.") + return + } - let tag = tags.first! - session.connect(to: tag, completionHandler: { (error: Error?) in - guard error == nil else { - session.invalidate(errorMessage: "Unable to connect to tag.") - return - } + switch ndefStatus { + case .notSupported: + session.invalidate(errorMessage: "Tag is not NDEF compliant.") + + case .readOnly: + guard sessionType == .read else { + session.invalidate(errorMessage: "Tag is read only.") + return + } + read(tag: tag, session: session) + + case .readWrite: + switch sessionType { + case .read: + read(tag: tag, session: session) - tag.queryNDEFStatus(completionHandler: { [weak self] (ndefStatus: NFCNDEFStatus, capacity: Int, error: Error?) in - guard let self else { return } - - guard error == nil else { - session.invalidate(errorMessage: "Unable to query the NDEF status of tag.") - return - } - - switch ndefStatus { - case .notSupported: - session.invalidate(errorMessage: "Tag is not NDEF compliant.") - - case .readOnly: - guard sessionType == .read else { - session.invalidate(errorMessage: "Tag is read only.") - return - } - read(tag: tag, session: session) - - case .readWrite: - switch sessionType { - case .read: - read(tag: tag, session: session) - - case .write: - let data = writeMesage.data(using: .utf8)! - let payload = NFCNDEFPayload(format: .nfcWellKnown, type: Data("T".utf8), identifier: Data(), payload: data) - let message = NFCNDEFMessage(records: [payload]) - tag.writeNDEF(message, completionHandler: { (error: Error?) in - if nil != error { - session.invalidate(errorMessage: "Write NDEF message fail: \(error!)") - } else { - session.alertMessage = "Write NDEF message successful." - session.invalidate() - } - }) - case .lock: - session.alertMessage = "The tag locking has been completed." - session.invalidate() - } - - @unknown default: - session.alertMessage = "Unknown NDEF tag status." - session.invalidate() - } + case .write: + let data = writeMesage.data(using: .utf8)! + let payload = NFCNDEFPayload(format: .nfcWellKnown, type: Data("T".utf8), identifier: Data(), payload: data) + let message = NFCNDEFMessage(records: [payload]) + tag.writeNDEF(message, completionHandler: { (error: Error?) in + if nil != error { + session.invalidate(errorMessage: "Write NDEF message fail: \(error!)") + } else { + session.alertMessage = "Write NDEF message successful." + session.invalidate() + } }) - }) - } + case .lock: + session.alertMessage = "The tag locking has been completed." + session.invalidate() + } + + @unknown default: + session.alertMessage = "Unknown NDEF tag status." + session.invalidate() + } + }) + }) + } } extension NFCTagReader: NFCTagReaderSessionDelegate { - func tagReaderSessionDidBecomeActive(_ session: NFCTagReaderSession) { - print("Reader session is active.") - } + func tagReaderSessionDidBecomeActive(_ session: NFCTagReaderSession) { + print("Reader session is active.") + } + + func tagReaderSession(_ session: NFCTagReaderSession, didInvalidateWithError error: Error) { + print("error:\(error.localizedDescription)") + } + + func tagReaderSession(_ session: NFCTagReaderSession, didDetect tags: [NFCTag]) { + let tag = tags.first! - func tagReaderSession(_ session: NFCTagReaderSession, didInvalidateWithError error: Error) { - print("error:\(error.localizedDescription)") - } - - func tagReaderSession(_ session: NFCTagReaderSession, didDetect tags: [NFCTag]) { - let tag = tags.first! - - session.connect(to: tag) { (error) in - if nil != error { - session.invalidate(errorMessage: "Unable to connect to tag.") - return - } - - guard case .feliCa(let feliCaTag) = tag else { - let retryInterval = DispatchTimeInterval.milliseconds(500) - session.alertMessage = "A tag that is not FeliCa is detected, please try again with tag FeliCa." - DispatchQueue.global().asyncAfter(deadline: .now() + retryInterval, execute: { - session.restartPolling() - }) - return - } - - let idm = feliCaTag.currentIDm.map { String(format: "%.2hhx", $0) }.joined() - DispatchQueue.main.async { [weak self] in - self?.readMessage = idm - } - session.alertMessage = "The tag reading has been completed." - session.invalidate() - } + session.connect(to: tag) { (error) in + if nil != error { + session.invalidate(errorMessage: "Unable to connect to tag.") + return + } + + guard case .feliCa(let feliCaTag) = tag else { + let retryInterval = DispatchTimeInterval.milliseconds(500) + session.alertMessage = "A tag that is not FeliCa is detected, please try again with tag FeliCa." + DispatchQueue.global().asyncAfter(deadline: .now() + retryInterval, execute: { + session.restartPolling() + }) + return + } + + let idm = feliCaTag.currentIDm.map { String(format: "%.2hhx", $0) }.joined() + DispatchQueue.main.async { [weak self] in + self?.readMessage = idm + } + session.alertMessage = "The tag reading has been completed." + session.invalidate() } + } } diff --git a/CoreNFCSampler/Utility.swift b/CoreNFCSampler/Utility.swift index e031a14..82a73b0 100644 --- a/CoreNFCSampler/Utility.swift +++ b/CoreNFCSampler/Utility.swift @@ -9,14 +9,14 @@ import Foundation enum SessionType: String, CaseIterable, Identifiable { - case read - case write - case lock - var id: String { rawValue } + case read + case write + case lock + var id: String { rawValue } } enum NFCFormat: String, CaseIterable, Identifiable { - case ndef - case suica - var id: String { rawValue } + case ndef + case suica + var id: String { rawValue } }