# iOS Demo

本 Demo 展示如何在 iOS 应用中集成和使用 NFCSDK 来操作 NFC 智能设备。

## 快速开始

### 1. 集成 SDK

将 SDK xcframework 集成到你的 iOS 项目中：

1. 在 Xcode 中打开你的项目
2. 选择 Build Phases → Link Binary With Libraries
3. 点击 "+" 添加 `NFCSDK.xcframework`

### 2. 添加 NFC 权限

在 `Info.plist` 中添加：

```xml
<key>NFCReaderUsageDescription</key>
<string>需要使用 NFC 来操作智能设备</string>

<key>com.apple.developer.nfc.readersession.formats</key>
<array>
    <string>NDEF</string>
    <string>TAG</string>
</array>
```

在项目的 Signing & Capabilities 中添加 NFC capability。

### 3. 初始化 SDK

在你的 ViewModel 中实现 `IOSNFCCallbacks` 回调接口并初始化 NFCHelper 类：

```swift
import Combine
import NFCSDK

class NFCViewModel: ObservableObject, IOSNFCCallbacks {
    @Published var deviceId = ""
    @Published var deviceRssi = ""
    @Published var devicePassword = "123456"
    
    private lazy var nfcHelper = IOSNFCHelper(callback: self)
    
    // 设备发现时调用，如需请求接口请使用异步的方式，不要阻塞该回调函数
    func discovered(id: String, isNew: Bool, rssi: Int32) {
        DispatchQueue.main.async {
            self.deviceId = id
            self.deviceRssi = String(rssi)
        }
    }
    
    // 操作完成时调用
    func finished() {
        DispatchQueue.main.async {
            self.deviceId = ""
            self.deviceRssi = ""
        }
    }
    
    // 获取设备充电进度
    func charging(res: String, level: Int32) {
        switch res {
        case "OK":
            print("Charging level: \(level)%")
        case "UNAUTHORIZED":
            print("Authentication failed")
        case "ERROR":
            print("Failed to get charging level")
        default:
            break
        }
    }
    
    // 控制操作（开锁/关锁）的结果
    func controlling(res: String, progress: Int32, ctrl: String) {
        switch res {
        case "OK":
            print("Control successful: \(ctrl)")
        case "UNAUTHORIZED":
            print("Authentication failed")
        case "ERROR":
            print("Control failed")
        default:
            break
        }
    }
    
    // 设置密码的结果
    func setKey(res: String, password: String) {
        switch res {
        case "OK":
            print("Password set successfully")
        case "UNAUTHORIZED":
            print("Authentication failed")
        case "ERROR":
            print("Failed to set password")
        default:
            break
        }
    }
    
    // 读写自定义数据的结果
    // config 标识本次操作类型（.write / .read）
    // 读成功时 data 为设备返回的 56 字节数据；写成功时 data 为写入的数据
    func customData(res: String, config: CustomDataConfig, data: Data?) {
        switch res {
        case "OK":
            print("Custom data \(config.name) successful")
        case "ERROR":
            print("Custom data \(config.name) failed")
        default:
            break
        }
        if let data0 = data {
            print(data0.map { String(format: "%02X", $0) }.joined(separator: " "))
        }
    }
    
    // 开锁操作
    func mUnlock() {
        nfcHelper.unlock(password: devicePassword)
        nfcHelper.startScan()
    }
    
    // 关锁操作
    func mLock() {
        nfcHelper.lock(password: devicePassword)
        nfcHelper.startScan()
    }
    
    // 设置密码操作
    func mSetKey(sKey: String) {
        nfcHelper.setKey(password: devicePassword, sKey: sKey)
        nfcHelper.startScan()
    }
    
    // 写自定义数据操作（数据必须是 56 字节）
    func mWriteCustomData(data: Data) {
        nfcHelper.customDataOperation(config: .write, customData: data)
        nfcHelper.startScan()
    }
    
    // 读自定义数据操作（读操作 customData 传 nil）
    func mReadCustomData() {
        nfcHelper.customDataOperation(config: .read, customData: nil)
        nfcHelper.startScan()
    }
}
```

## 核心功能

### 开锁

```swift
// 执行开锁操作，需要正确的密码验证
nfcHelper.unlock(password: "123456")
nfcHelper.startScan()
```

### 关锁

```swift
// 执行关锁操作，需要正确的密码验证
nfcHelper.lock(password: "123456")
nfcHelper.startScan()
```

### 设置密码

```swift
// 为设备设置新的密码
// password: 新的设备密码
// sKey: 管理员密码
nfcHelper.setKey(password: "654321", sKey: "")
nfcHelper.startScan()
```

### 读写自定义数据

设备提供 56 字节的自定义数据存储区，可用于保存业务自定义信息。读写结果通过 `customData()` 回调返回。

```swift
// 写自定义数据：customData 必须是 56 字节，否则会抛出异常
nfcHelper.customDataOperation(config: .write, customData: Data(repeating: 0x80, count: 56))
nfcHelper.startScan()

// 读自定义数据：读操作无需传入数据，customData 传 nil 即可
nfcHelper.customDataOperation(config: .read, customData: nil)
nfcHelper.startScan()
```

操作完成后在 `customData()` 回调中获取结果：

- 写成功时，回调的 `data` 为写入的 56 字节数据
- 读成功时，回调的 `data` 为设备返回的 56 字节数据

### 获取设备信息

通过回调接口获取设备的实时信息：

- **设备 ID**：`discovered()` 回调中的 `id` 参数
- **信号强度**：`discovered()` 回调中的 `rssi` 参数
- **充电进度**：`charging()` 回调中的 `level` 参数

## 回调接口说明

### IOSNFCCallbacks

| 方法 | 参数 | 说明 |
|------|------|------|
| `discovered()` | `id: String, isNew: Bool, rssi: Int32` | 设备发现时调用 |
| `finished()` | - | 操作完成时调用 |
| `charging()` | `res: String, level: Int32` | 获取充电进度时调用 |
| `controlling()` | `res: String, progress: Int32, ctrl: String` | 控制操作完成时调用 |
| `setKey()` | `res: String, password: String` | 设置密码操作完成时调用 |
| `customData()` | `res: String, config: CustomDataConfig, data: Data?` | 读写自定义数据完成时调用 |

### Result 值

| 值 | 说明 |
|---|------|
| `"OK"` | 操作成功 |
| `"UNAUTHORIZED"` | 验证失败（如密码错误） |
| `"ERROR"` | 操作失败（如设备断开连接） |

### CustomDataConfig 枚举

| 值 | 说明 |
|---|------|
| `.write` | 写自定义数据 |
| `.read` | 读自定义数据 |

## 开发流程

1. **集成 SDK**：将 xcframework 文件添加到项目
2. **配置权限**：在 Info.plist 中配置 NFC 权限，添加 NFC capability
3. **实现回调接口**：让 ViewModel 遵循 `IOSNFCCallbacks` 协议
4. **初始化助手类**：创建 `IOSNFCHelper` 实例，传入 `self` 作为回调
5. **处理回调**：在各回调方法中更新 UI 状态或处理业务逻辑
6. **调用操作**：调用 `unlock()`、`lock()`、`setKey()` 或 `customDataOperation()` 方法
7. **启动扫描**：调用 `startScan()` 开始 NFC 扫描
8. **线程安全**：在主线程上更新 UI，使用 `DispatchQueue.main.async`
9. **测试**：在真实 NFC 设备上进行测试

## SwiftUI 集成示例

```swift
import SwiftUI

struct ContentView: View {
    @StateObject var model = NFCViewModel()
    
    var body: some View {
        NavigationStack {
            Form {
                Section(header: Text("设备信息")) {
                    TextField("设备 ID", text: $model.deviceId)
                        .disabled(true)
                    TextField("信号强度", text: $model.deviceRssi)
                        .disabled(true)
                }
                
                Section(header: Text("密码")) {
                    SecureField("输入密码", text: $model.devicePassword)
                }
                
                Section(header: Text("操作")) {
                    Button("开锁") {
                        model.mUnlock()
                    }
                    
                    Button("关锁") {
                        model.mLock()
                    }
                    
                    Button("设置密码") {
                        model.mSetKey(sKey: "")
                    }
                    
                    Button("写自定义数据") {
                        model.mWriteCustomData(data: Data(repeating: 0x80, count: 56))
                    }
                    
                    Button("读自定义数据") {
                        model.mReadCustomData()
                    }
                }
            }
        }
    }
}
```

## 完整示例

详见本 Demo 项目中的 `NFCViewModel.swift` 和 `ContentView.swift`，展示了完整的开发示例。

## 运行 Demo

```bash
# 使用 Xcode 打开项目
open IOSDemo.xcodeproj

# 或使用命令行构建
xcodebuild -scheme IOSDemo -configuration Debug

# 在真实设备上运行
xcodebuild -scheme IOSDemo -configuration Debug -destination 'generic/platform=iOS'
```

## 系统要求

- iOS 13.0 或更高版本
- 支持 NFC 的 iPhone 设备（iPhone 7 及更新）
- Xcode 15.0 或更高版本
- 真实设备运行（模拟器不支持 NFC）

## 常见问题

**Q: 模拟器上无法运行？**
- NFC 功能不支持在模拟器上运行，需要在真实设备上测试

**Q: NFC 权限提示不出现？**
- 确保已在 Info.plist 中添加 `NFCReaderUsageDescription`
- 确保已在 Signing & Capabilities 中添加 NFC capability

**Q: 设备无法被发现？**
- 确保调用了 `startScan()` 开始扫描
- 确保设备距离足够近（通常在 10cm 以内）
- 检查应用是否拥有 NFC 权限

**Q: 如何确保线程安全？**
- 在回调方法中使用 `DispatchQueue.main.async` 来更新 UI
- 避免直接在回调中修改 @Published 变量

**Q: 验证失败或操作失败？**
- 确保输入的密码正确
- 查看 `res` 参数的值判断具体失败原因
- 在 `controlling()` 或 `charging()` 回调中获取详细的错误信息

**Q: 如何判断操作是否成功？**
- 通过 `res` 参数的值判断操作结果：`"OK"` 表示成功
- 其他回调（`controlling()`、`charging()`、`setKey()`）中的 `res` 参数指示操作状态
