diff --git a/NfcLock.Ios.Binding/ApiDefinition.cs b/NfcLock.Ios.Binding/ApiDefinition.cs index 19307c4..8089a7c 100644 --- a/NfcLock.Ios.Binding/ApiDefinition.cs +++ b/NfcLock.Ios.Binding/ApiDefinition.cs @@ -7,39 +7,48 @@ namespace NfcLock.Ios.Binding [DisableDefaultCtor] interface NFCManager { - // -(void)startScan; + // +(void)startScan; + [Static] [Export ("startScan")] void StartScan (); - // -(void)endScan; + // +(void)endScan; + [Static] [Export ("endScan")] void EndScan (); - // -(void)endScanWithErrorMessage:(NSString * _Nonnull)errorMessage; + // +(void)endScanWithErrorMessage:(NSString * _Nonnull)errorMessage; + [Static] [Export ("endScanWithErrorMessage:")] void EndScanWithErrorMessage (string errorMessage); - // -(void)setLoopCbWithCb:(id)cb; + // +(void)setLoopCbWithCb:(id)cb; + [Static] [Export ("setLoopCbWithCb:")] void SetLoopCbWithCb (NSObject cb); - // -(void)setFinishedCbWithCb:(void (^ _Nonnull)(void))cb; + // +(void)setFinishedCbWithCb:(void (^ _Nonnull)(void))cb; + [Static] [Export ("setFinishedCbWithCb:")] void SetFinishedCbWithCb (Action cb); - // -(void)setChargingCbWithCb:(void (^ _Nonnull)(NSString * _Nonnull, int))cb; + // +(void)setChargingCbWithCb:(void (^ _Nonnull)(NSString * _Nonnull, int))cb; + [Static] [Export ("setChargingCbWithCb:")] void SetChargingCbWithCb (Action cb); - // -(void)setControllingCbWithCb:(void (^ _Nonnull)(NSString * _Nonnull, int))cb; + // +(void)setControllingCbWithCb:(void (^ _Nonnull)(NSString * _Nonnull, int))cb; + [Static] [Export ("setControllingCbWithCb:")] void SetControllingCbWithCb (Action cb); - // -(void)lockWithPassword:(NSString * _Nonnull)password; + // +(void)lockWithPassword:(NSString * _Nonnull)password; + [Static] [Export ("lockWithPassword:")] void LockWithPassword (string password); - // -(void)unlockWithPassword:(NSString * _Nonnull)password; + // +(void)unlockWithPassword:(NSString * _Nonnull)password; + [Static] [Export ("unlockWithPassword:")] void UnlockWithPassword (string password); } diff --git a/NfcLock.Ios.Binding/NfcLockFramework/NfcLockFramework.xcodeproj/project.xcworkspace/xcuserdata/apple.xcuserdatad/UserInterfaceState.xcuserstate b/NfcLock.Ios.Binding/NfcLockFramework/NfcLockFramework.xcodeproj/project.xcworkspace/xcuserdata/apple.xcuserdatad/UserInterfaceState.xcuserstate index 88eb74d..3da535e 100644 Binary files a/NfcLock.Ios.Binding/NfcLockFramework/NfcLockFramework.xcodeproj/project.xcworkspace/xcuserdata/apple.xcuserdatad/UserInterfaceState.xcuserstate and b/NfcLock.Ios.Binding/NfcLockFramework/NfcLockFramework.xcodeproj/project.xcworkspace/xcuserdata/apple.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/NfcLock.Ios.Binding/NfcLockFramework/NfcLockFramework/NfcLockFramework.swift b/NfcLock.Ios.Binding/NfcLockFramework/NfcLockFramework/NfcLockFramework.swift index a22fd31..7f8e9f0 100644 --- a/NfcLock.Ios.Binding/NfcLockFramework/NfcLockFramework/NfcLockFramework.swift +++ b/NfcLock.Ios.Binding/NfcLockFramework/NfcLockFramework/NfcLockFramework.swift @@ -3,32 +3,88 @@ import NFCSDK @objc(NFCManager) public class NFCManager: NSObject, NFCTagReaderSessionDelegate { + // 单例实例(改为实例属性,而非直接用 static 方法) static let instance = NFCManager() - private let helper = IOSNFCHelper() - private var session: NFCTagReaderSession? - private var readyToStart = true - private var controlName = "" + // NFCSDK 助手(改为实例属性) + let helper = IOSNFCHelper() + // NFC 会话(改为实例属性) + var session: NFCTagReaderSession? + // 控制状态(改为实例属性) + var readyToStart = true + var controlName = "" private override init() { - + super.init() + } + + // MARK: - 对外暴露的 OC 调用方法(通过单例调用实例方法) + @objc + public static func startScan() { + instance._startScan() } @objc - public func startScan() { - if (readyToStart) { + public static func endScan() { + instance._endScan() + } + + @objc + public static func endScan(errorMessage: String) { + instance._endScan(errorMessage: errorMessage) + } + + @objc + public static func setLoopCb(cb: @escaping (String, Bool, Int) -> Bool) { + instance._setLoopCb(cb: cb) + } + + @objc + public static func setFinishedCb(cb: @escaping () -> Void) { + instance._setFinishedCb(cb: cb) + } + + @objc + public static func setChargingCb(cb: @escaping (String, Int) -> Void) { + instance._setChargingCb(cb: cb) + } + + @objc + public static func setControllingCb(cb: @escaping (String, Int) -> Void) { + instance._setControllingCb(cb: cb) + } + + @objc + public static func lock(password: String) { + instance._lock(password: password) + } + + @objc + public static func unlock(password: String) { + instance._unlock(password: password) + } + + // MARK: - 实际的实例方法(核心逻辑) + private func _startScan() { + // 1. 检查设备是否支持 NFC + guard NFCTagReaderSession.readingAvailable else { + _endScan(errorMessage: "设备不支持NFC功能") + return + } + + if readyToStart { readyToStart = false + // 2. 修复语法错误:移除末尾多余的逗号 session = NFCTagReaderSession( pollingOption: [.iso14443], - delegate: self, - queue: nil, + delegate: self, // 这里必须传实例 self,而非静态的 self + queue: nil ) session?.alertMessage = "请将 iPhone 靠近设备" session?.begin() } } - @objc - public func endScan() { + private func _endScan() { session?.invalidate() Task { try? await Task.sleep(nanoseconds: 2_000_000_000) @@ -36,8 +92,7 @@ public class NFCManager: NSObject, NFCTagReaderSessionDelegate { } } - @objc - public func endScan(errorMessage: String) { + private func _endScan(errorMessage: String) { session?.invalidate(errorMessage: errorMessage) Task { try? await Task.sleep(nanoseconds: 2_000_000_000) @@ -45,28 +100,98 @@ public class NFCManager: NSObject, NFCTagReaderSessionDelegate { } } + private func _setLoopCb(cb: @escaping (String, Bool, Int) -> Bool) { + helper.setLoopCb { id, isNew, rssi in + let isNew0 = isNew.boolValue + let rssi0 = rssi?.intValue ?? 0 + self.session?.alertMessage = "检测到设备" + return KotlinBoolean(bool: cb(id, isNew0, rssi0)) + } + } + + private func _setFinishedCb(cb: @escaping () -> Void) { + helper.setFinishedCb(cb: { + self._endScan() + cb() + }) + } + + private func _setChargingCb(cb: @escaping (String, Int) -> Void) { + helper.setChargingCb { res, level in + let level0 = level?.intValue ?? 0 + switch res { + case "OK": + self.session?.alertMessage = "充电中(\(level0)%)" + case "UNAUTHORIZED": + self._endScan(errorMessage: "验证失败") + default: + self._endScan(errorMessage: "NFC 标签丢失") + } + cb(res, level0) + } + } + + private func _setControllingCb(cb: @escaping (String, Int) -> Void) { + helper.setControllingCb { res, progress in + let progress0 = progress?.intValue ?? 0 + switch res { + case "OK": + if progress0 < 100 { + self.session?.alertMessage = "\(self.controlName)中(\(progress0)%)" + } else { + self.session?.alertMessage = "\(self.controlName)成功" + } + default: + self._endScan(errorMessage: "\(self.controlName)失败") + } + cb(res, progress0) + } + } + + private func _lock(password: String) { + controlName = "关锁" + helper.lock(password: password) + } + + private func _unlock(password: String) { + controlName = "开锁" + helper.unlock(password: password) + } + + // MARK: - NFCTagReaderSessionDelegate 协议方法(必须是实例方法) + // 1. 可选方法:会话激活时调用(非必选,但建议保留) public func tagReaderSessionDidBecomeActive(_ session: NFCTagReaderSession) { print("NFC Session Active") } + // 2. 必选方法:会话失效/出错时调用 public func tagReaderSession(_ session: NFCTagReaderSession, didInvalidateWithError error: Error) { - endScan() + // 区分用户主动取消和真实错误 + if let nfcError = error as? NFCReaderError { + if nfcError.code != .readerSessionInvalidationErrorUserCanceled { + print("NFC 会话错误: \(nfcError.localizedDescription)") + } + } + _endScan() } + // 3. 必选方法:检测到 NFC 标签时调用 public func tagReaderSession(_ session: NFCTagReaderSession, didDetect tags: [CoreNFC.NFCTag]) { + guard let tag = tags.first else { + _endScan(errorMessage: "未检测到有效NFC标签") + return + } - guard let tag = tags.first else { return } - - session.connect(to: tag) { error in - if error != nil { - self.endScan(errorMessage: "NFC 连接失败") + session.connect(to: tag) { [weak self] error in + guard let self = self else { return } // 避免循环引用 + + if let error = error { + self._endScan(errorMessage: "NFC 连接失败: \(error.localizedDescription)") return } switch tag { - case .miFare(let miFareTag): - self.helper.setTransceiver { data, resolve in let length = Int(data.size) var buffer = [UInt8](repeating: 0, count: length) @@ -76,8 +201,8 @@ public class NFCManager: NSObject, NFCTagReaderSessionDelegate { let command = Data(buffer) miFareTag.sendMiFareCommand(commandPacket: command) { response, error in - if error != nil { - self.endScan(errorMessage: "NFC 标签丢失") + if let error = error { + self._endScan(errorMessage: "NFC 标签丢失: \(error.localizedDescription)") let _ = resolve(KotlinByteArray(size: 0)) return } @@ -94,81 +219,13 @@ public class NFCManager: NSObject, NFCTagReaderSessionDelegate { do { try await self.helper.process() } catch { - print("process error") + print("process error: \(error.localizedDescription)") } } - default: - self.endScan(errorMessage: "不是 NFC-A 标签") + self._endScan(errorMessage: "不是 NFC-A 标签") } } } - - @objc - public func setLoopCb(cb: @escaping (String, Bool, Int) -> Bool) { - helper.setLoopCb { id, isNew, rssi in - let isNew0 = isNew.boolValue - let rssi0 = rssi?.intValue ?? 0 - self.session?.alertMessage = "检测到设备" - return KotlinBoolean(bool: cb(id, isNew0, rssi0)) - } - } - - @objc - public func setFinishedCb(cb: @escaping () -> Void) { - helper.setFinishedCb(cb: { - self.endScan() - cb() - }) - } - - @objc - public func setChargingCb(cb: @escaping (String, Int) -> Void) { - helper.setChargingCb { res, level in - let level0 = level?.intValue ?? 0 - switch (res) { - case "OK": - self.session?.alertMessage = "充电中(\(level0)%)" - break - case "UNAUTHORIZED": - self.endScan(errorMessage: "验证失败") - break - default: - self.endScan(errorMessage: "NFC 标签丢失") - } - cb(res, level0) - } - } - - @objc - public func setControllingCb(cb: @escaping (String, Int) -> Void) { - helper.setControllingCb { res, progress in - let progress0 = progress?.intValue ?? 0 - switch (res) { - case "OK": - if (progress0 < 100) { - self.session?.alertMessage = "\(self.controlName)中(\(progress0)%)" - } else { - self.session?.alertMessage = "\(self.controlName)成功" - } - break - default: - self.endScan(errorMessage: "\(self.controlName)失败") - } - cb(res, progress0) - } - } - - @objc - public func lock(password: String) { - controlName = "关锁" - helper.lock(password: password) - } - - @objc - public func unlock(password: String) { - controlName = "开锁" - helper.unlock(password: password) - } }