Go small with Embedded Swift
SwiftUI & UI Frameworks 进阶 20m

用 Embedded Swift 给微控制器写程序

Go small with Embedded Swift

2024年6月10日

在 Apple 官方观看视频

一句话判断

Embedded Swift 是 Swift 的一个子集编译模式,可以直接跑在 ESP32 等 RISC-V 微控制器上——Apple 自己的 Secure Enclave 也在用,配合 C/C++ SDK 和 Matter 协议能构建完整的智能家居配件。

这场 Session 讲了什么

Swift 已经覆盖了移动端、桌面端和服务器,今年 Apple 把它带到了嵌入式设备。我们身边的智能灯泡、温控器、传感器大多用 C/C++ 编写微控制器程序。Embedded Swift 让你用 Swift 来写这些程序,同时享受 Swift 的类型安全、可选值、闭包等语言特性。

Embedded Swift 是 Swift 的一个子集,保留了值类型、引用类型、闭包、可选值、错误处理、泛型等核心特性。它不是源码稳定的功能(目前是实验性的),需要从 swift.org 下载预览工具链。

Demo 展示了完整的开发流程:用 ESP32-C6 开发板(RISC-V 架构),通过 CMake 构建系统将 Swift 代码编译为固件,通过 USB 烧录到设备。关键点是 Swift 可以通过 bridging header 直接调用厂商 SDK 的 C API,也可以通过 C++ 互操作使用 Matter 协议。

Apple 自家也在用 Embedded Swift——Secure Enclave Processor 上运行的就是 Embedded Swift 代码。内存安全在安全关键场景中的价值不言而喻。

值得深挖的点

从 C API 到 Swift 封装的开发范式

Demo 展示了一种很实用的开发模式。第一步是直接调用厂商 SDK 的 C API 来控制硬件,这能快速验证功能。第二步是把这些 C API 封装成 Swift 风格的接口——把整数参数变成有语义的类型,把不安全的指针操作封装为安全的属性访问。

比如 LED 控制的 C API 需要传入颜色值、饱和度、亮度三个整数参数。封装后的 Swift 版本提供了 led.enabled(布尔值)、led.brightness(0-100 的整数)和 led.color(带语义的颜色类型)这样的接口。应用层代码从”调用一组不直观的函数”变成了”设置几个可读的属性”。

这种分层不是强制的,但非常推荐。C API 层保证了兼容性和可移植性,Swift 封装层提升了可读性和安全性。对于 Matter 这类复杂的 C++ 协议栈,这种封装更有价值——开发者不需要理解 Matter 的内部实现,只需要用 Swift 风格的 API 控制设备。

Embedded Swift 的限制与取舍

作为 Swift 子集,有些东西被舍弃了。目前 Embedded Swift 不支持运行时反射、部分高级泛型特性、和一些标准库中依赖运行时特性的模块。这是为了在资源受限的微控制器上运行——不需要完整的 Swift 运行时。

项目结构也有额外的模板文件:YAML 配置、CSV 文件和 sdkconfig 文件,这些都是厂商 SDK 构建系统需要的。虽然 Swift 代码本身很简洁,但项目配置仍然需要理解目标平台的构建流程。

代码片段

LED 控制的 Swift 封装

// 封装 C API 为 Swift 风格接口
struct LED {
    var enabled: Bool {
        didSet {
            // 调用厂商 SDK 的 C 函数
            led_set_enabled(enabled ? 1 : 0)
        }
    }
    
    var brightness: Int {
        didSet {
            // 亮度范围 0-100,类型安全
            led_set_brightness(Int32(clamping: brightness))
        }
    }
    
    func setColor(hue: Double, saturation: Double) {
        led_set_hsv(Float(hue), Float(saturation), Float(brightness))
    }
}

场景:将厂商 SDK 的 LED 控制 API 封装为直观的 Swift 接口,应用层代码不需要关心底层函数签名。

应用层逻辑

// 使用封装后的 LED 接口——代码可读性极高
let led = LED()
led.brightness = 80

while true {
    sleep(1)
    led.enabled.toggle()
    
    if led.enabled {
        // 每次亮灯时随机选一个颜色
        let hue = Double.random(in: 0...360)
        led.setColor(hue: hue, saturation: 1.0)
    }
}

场景:LED 闪烁并随机变色。这行代码跟写普通 iOS Swift 没什么区别,但它实际运行在一个 RISC-V 微控制器上。

通过 Matter 协议接入 HomeKit

// 使用 Matter 协议(C++ SDK 通过互操作调用)
// Matter 处理设备发现、配网、远程控制等基础设施
// 开发者只需定义配件的行为

// Swift 侧:当 Home App 发来控制指令时
func handleMatterCommand(onOff: Bool) {
    led.enabled = onOff
}

// Swift 侧:当配件状态变化时通知 Matter
func notifyMatterStateChange() {
    matter_report_attribute_change(/* 参数 */)
}

场景:ESP32 设备通过 Matter 协议加入 HomeKit 网络,iPhone 上的 Home App 可以直接控制 LED 开关。

坑点:Matter 的 C++ API 需要 Swift 的 C++ 互操作功能,确保工具链版本支持。设备需要先配网(commissioning)才能加入 HomeKit。

最佳实践

  • 使用 swift.org 的预览工具链,Embedded Swift 目前未包含在 Xcode 正式版中
  • 项目模板基于厂商 SDK,先用 SDK 的示例项目跑通,再逐步替换为 Swift
  • C API 封装为 Swift 接口是关键步骤,不要在应用层直接调用 C 函数
  • Neovim + LSP 可以获得完整的补全和定义跳转体验,不依赖 Xcode
  • Matter 协议是智能家居配件的最佳选择,省去了自己实现设备发现和配网的成本

还有什么值得关注

  • Embedded Swift 目前是实验性功能,源码稳定性尚未保证,API 可能在后续版本变化
  • Apple 的 Secure Enclave Processor 已经在生产环境使用 Embedded Swift,说明成熟度在提升
  • WWDC 2021 有专门介绍 Matter 协议的 Session,建议作为前置知识观看
WWDC 2024