随着Apple Vision Pro的发布,visionOS开发成了一个热门的新领域。

我最近在做一个visionOS应用的项目,从环境搭建到功能开发,踩了不少坑,也积累了不少经验。visionOS是一个全新的操作系统,开发方式和iOS有相似之处,但也有很多独特的地方,特别是空间计算、手势交互、沉浸式体验这些方面。

这篇文章就来详细介绍一下visionOS开发的配置流程,从基础的环境搭建到高级的功能配置,希望能给想入门visionOS开发的朋友一些参考。

开发前的准备

在开始visionOS开发之前,需要做一些准备工作。

第一,硬件要求。visionOS开发需要一台Mac电脑,最好是Apple Silicon的Mac(M1及以上),因为模拟器和构建工具对性能要求比较高。Intel Mac也能开发,但速度会慢一些。系统需要macOS 14.4(Sonoma)及以上版本。

如果有条件的话,最好有一台Apple Vision Pro真机。虽然模拟器能做大部分开发和测试,但真机的体验和模拟器还是有差距的,特别是手势交互、空间感知、眼动追踪这些功能,必须在真机上才能准确测试。

第二,Apple开发者账号。开发visionOS应用需要Apple开发者账号(个人版每年99美元),才能在真机上运行和发布应用。如果只是在模拟器上学习,可以不用账号,但要发布到App Store就必须有。

第三,了解Swift和SwiftUI。visionOS的开发主要用Swift和SwiftUI,如果你有iOS开发经验,上手会很快。如果没有,建议先学一下Swift语言和SwiftUI框架,这是visionOS开发的基础。

第四,了解空间计算的概念。visionOS和传统的操作系统不一样,它是一个空间计算平台,应用是运行在三维空间中的。需要理解空间、窗口、体积、沉浸式空间这些概念,才能设计和开发出好的visionOS应用。

环境搭建

准备工作做好之后,开始搭建开发环境。

第一步,安装Xcode。visionOS开发需要Xcode 15.2及以上版本。可以在Mac App Store里下载,或者在Apple开发者网站下载。安装的时候,要确保安装了visionOS的SDK和模拟器。Xcode 15.2默认会包含visionOS SDK,但如果是从旧版本升级的,可能需要手动下载。

第二步,安装visionOS模拟器。打开Xcode,进入Settings -> Platforms,看看有没有visionOS模拟器。如果没有,点击"+"号,选择visionOS,下载安装。模拟器的体积比较大(十几个GB),下载需要一些时间。

第三步,配置Apple Vision Pro真机(如果有的话)。用USB-C线把Vision Pro连接到Mac,打开Vision Pro,在设置里开启开发者模式。然后在Xcode的设备列表里选择Vision Pro,等待Xcode准备好开发支持。第一次连接的时候,需要在Vision Pro上信任这台Mac。

第四步,验证环境。打开Xcode,创建一个新的项目,选择visionOS -> App,用默认配置创建一个Hello World项目,然后在模拟器上运行。如果能正常编译并在模拟器里看到一个窗口,说明环境搭建成功了。

创建第一个项目

环境搭好之后,创建第一个visionOS项目。

打开Xcode,选择File -> New -> Project,在左侧选择visionOS,然后选择App模板。点击Next,填写项目信息:

  • Product Name:项目名称
  • Team:你的开发者团队(没有的话可以选None)
  • Organization Identifier:组织标识符,一般用反域名格式
  • Interface:选择SwiftUI(visionOS推荐用SwiftUI)
  • Language:选择Swift
  • Storage:选择None(如果不需要Core Data的话)

点击Next,选择项目保存的位置,创建项目。

创建好的项目,默认会有几个文件:

  • ContentView.swift:主界面视图
  • <项目名>App.swift:应用入口
  • Assets.xcassets:资源文件
  • Info.plist:应用配置

默认的ContentView里会有一个简单的窗口,显示一个"Hello World"的标签。点击运行,在模拟器里就能看到一个悬浮在空间中的窗口,上面写着"Hello World"。

这就是最简单的visionOS应用了。接下来,我们来看看各种配置和功能。

基础配置

窗口配置

visionOS应用最基本的界面元素是窗口(Window)。窗口可以悬浮在空间中,用户可以用手势移动、缩放、关闭窗口。

在SwiftUI中,创建窗口很简单,用WindowGroup:

@main
struct MyApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

默认的窗口大小是系统决定的,但你可以用.frame修饰符来设置窗口的推荐大小:

ContentView()
    .frame(width: 600, height: 400)

还可以用.windowResizability修饰符来设置窗口是否可以调整大小:

.windowResizability(.contentSize) // 根据内容自动调整大小

交互配置

visionOS的交互方式和iOS不一样,主要是用眼神和手势。用户看着一个元素,然后捏合手指(拇指和食指捏一下),就相当于点击。

在SwiftUI中,大部分控件(Button、Toggle、Slider等)都自动支持眼动+手势的交互,不需要额外配置。但如果你用了自定义的视图,需要添加.tapAction或者用Button来包装,才能响应点击。

眼动追踪是visionOS的一个特色。系统会自动处理眼动的悬停效果(hover effect),但你可以用.hoverEffect修饰符来自定义悬停效果:

Image("myImage")
    .hoverEffect(.lift) // 悬停时图片浮起

空间配置

visionOS应用运行在用户的真实空间中,可以配置应用如何与真实空间交互。

在Info.plist里,可以设置应用的首选场景类型:

  • Mixed(混合):应用的窗口显示在真实环境中,用户可以看到周围的环境
  • Progressive(渐进):应用可以逐渐增加沉浸感,从混合到完全沉浸
  • Full(完全沉浸):应用完全占据用户的视野,看不到真实环境

默认是Mixed模式,如果需要沉浸式体验,需要在Info.plist里设置Preferred Scene Session Role为Immersive Space。

中级配置

体积(Volume)

除了普通的窗口,visionOS还支持体积(Volume)——一个三维的空间,用来显示3D内容。体积和窗口不同,它是三维的,用户可以从不同角度看里面的3D物体。

创建体积需要用WindowGroup的样式:

WindowGroup(id: "myVolume") {
    VolumeView()
}
.windowStyle(.volumetric)
.defaultSize(width: 600, height: 600, depth: 600)

在体积里,可以用RealityKit来显示3D模型。RealityKit是visionOS的3D渲染框架,支持加载USDZ格式的3D模型,添加物理效果、动画、粒子等。

import RealityKit

struct VolumeView: View {
    var body: some View {
        Model3D(named: "myModel") // 加载USDZ模型
            .padding()
    }
}

沉浸式空间(Immersive Space)

如果需要完全沉浸的体验(比如游戏、虚拟旅游、冥想应用),可以用沉浸式空间。沉浸式空间会完全占据用户的视野,看不到真实环境。

创建沉浸式空间,需要在App里定义一个ImmersiveSpace:

@main
struct MyApp: App {
    @State private var immersionStyle: ImmersionStyle = .full
    
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
        
        ImmersiveSpace(id: "immersive") {
            ImmersiveView()
        }
        .immersionStyle(selection: $immersionStyle, in: .full)
    }
}

然后在需要的时候打开沉浸式空间:

struct ContentView: View {
    @Environment(\.openImmersiveSpace) private var openImmersiveSpace
    
    var body: some View {
        Button("进入沉浸模式") {
            Task {
                await openImmersiveSpace(id: "immersive")
            }
        }
    }
}

在沉浸式空间里,可以用RealityKit创建完整的3D场景,添加天空、地面、物体、特效等。用户可以在虚拟空间中自由走动、观察、交互。

手势识别

visionOS支持多种手势:捏合(点击)、捏合拖动(拖拽)、双指捏合(缩放)、手掌张开(系统手势)等。

在SwiftUI中,可以用.gesture修饰符来添加自定义手势:

struct DragView: View {
    @GestureState private var offset: CGSize = .zero
    
    var body: some View {
        Image("myImage")
            .offset(offset)
            .gesture(
                DragGesture()
                    .updating($offset) { value, state, _ in
                        state = value.translation
                    }
            )
    }
}

对于更复杂的手势(比如双手手势、自定义手势),可以用UIKit的UIGestureRecognizer,或者用RealityKit的手势识别系统。

高级配置

空间锚点和平面检测

visionOS可以感知用户周围的环境,检测平面(桌面、地面、墙面),并在这些平面上放置虚拟物体。这需要用到ARKit的框架。

在visionOS中,ARKit的用法和iOS类似,但有一些区别。首先需要在Info.plist里申请空间感知权限(NSWorldSensingUsageDescription)。

然后用ARKit的PlaneDetection来检测平面:

import ARKit

@MainActor
class PlaneDetectionManager: ObservableObject {
    let session = ARKitSession()
    let planeProvider = PlaneDetectionProvider(alignments: [.horizontal, .vertical])
    
    func start() async {
        do {
            try await session.run([planeProvider])
            for await update in planeProvider.anchorUpdates {
                // 处理检测到的平面
                let anchor = update.anchor
                print("检测到平面: \(anchor.alignment)")
            }
        } catch {
            print("平面检测失败: \(error)")
        }
    }
}

检测到平面之后,可以用RealityKit在平面上放置3D物体,实现虚拟物体和真实环境的融合。

眼动追踪

visionOS有强大的眼动追踪功能,可以知道用户在看什么。这对于交互设计、注意力分析、无障碍功能都很有用。

眼动追踪需要在Info.plist里申请权限(NSEyeTrackingUsageDescription)。然后用ARKit的EyeTrackingProvider来获取眼动数据:

let eyeProvider = EyeTrackingProvider()

func startEyeTracking() async {
    do {
        try await session.run([eyeProvider])
        for await update in eyeProvider.anchorUpdates {
            let eyeAnchor = update.anchor
            // 获取左眼和右眼的位置和方向
            let leftEye = eyeAnchor.leftEyeTransform
            let rightEye = eyeAnchor.rightEyeTransform
            // 计算注视点
        }
    } catch {
        print("眼动追踪失败: \(error)")
    }
}

眼动数据可以用来做很多事情,比如根据用户的注视点来高亮UI元素、根据注视时间来触发交互、分析用户的注意力分布等。但要注意,眼动数据是敏感的隐私数据,要妥善处理,并且明确告知用户。

手部追踪

除了手势识别,visionOS还可以追踪手部的详细信息,比如每根手指的位置、关节的角度。这对于需要精细手部交互的应用(比如虚拟乐器、绘画、手术模拟)很有用。

手部追踪用ARKit的HandTrackingProvider:

let handProvider = HandTrackingProvider()

func startHandTracking() async {
    do {
        try await session.run([handProvider])
        for await update in handProvider.anchorUpdates {
            let handAnchor = update.anchor
            // 获取每根手指的关节位置
            for joint in handAnchor.handSkeleton?.allJoints ?? [] {
                let position = joint.originFromAnchorTransform
                // 处理关节位置
            }
        }
    } catch {
        print("手部追踪失败: \(error)")
    }
}

手部追踪的数据量很大,处理的时候要注意性能。一般来说,不需要每帧都处理所有关节,可以根据需要采样或者只处理关键关节。

空间音频

visionOS的音频是空间音频,声音有方向感和距离感,就像在真实世界中一样。这对于营造沉浸感非常重要。

在RealityKit中,可以给3D物体添加空间音频源:

let audioFile = try? AudioFileResource.load(named: "background.mp3")
if let audioFile = audioFile {
    let audioEntity = Entity()
    audioEntity.position = SIMD3<Float>(0, 1, -2)
    audioEntity.playAudio(audioFile)
}

空间音频会自动根据用户和音频源的相对位置来调整音量和方向,不需要手动计算。用户走到音频源的左边,声音就从左边来;走远了,声音就变小。

对于UI的音效,可以用AVFoundation的AVAudioPlayer,配合空间音频的配置,让UI声音也有空间感。

性能优化

visionOS应用对性能要求很高,因为需要实时渲染立体画面,还要处理空间感知、眼动追踪、手部追踪等。性能不好会导致帧率下降、画面卡顿,甚至让用户头晕。

性能优化的几个关键点:

第一,控制3D模型的面数。visionOS的GPU性能有限,3D模型的面数不要太高。复杂的模型可以用LOD(Level of Detail)技术,远处用低模,近处用高模。

第二,减少draw call。和其他3D应用一样,减少draw call能提升性能。可以合并材质、用实例化渲染(Instancing)来减少draw call。

第三,合理使用纹理。纹理的尺寸不要太大,用压缩格式。visionOS支持ASTC压缩格式,能在保证画质的同时减少内存占用。

第四,优化SwiftUI视图。避免在视图里做复杂的计算,用@State、@Observable等状态管理来减少不必要的刷新。对于复杂的UI,可以用UIKit或者Metal来渲染。

第五,监控性能。Xcode里有Instruments工具,可以分析visionOS应用的CPU、GPU、内存使用情况。定期做性能分析,找到瓶颈并优化。

发布配置

应用开发完成之后,需要发布到App Store。visionOS应用的发布流程和iOS类似,但有一些特殊的要求。

第一,应用截图。App Store需要visionOS应用的截图,截图必须在真机上截取,不能用模拟器的截图。截图要展示应用的核心功能和空间体验。

第二,应用描述。在App Store的描述里,要说明应用是visionOS应用,支持哪些功能(窗口、体积、沉浸式空间、空间交互等)。让用户知道这是一个空间计算应用,而不是普通的iOS应用。

第三,隐私权限。如果应用使用了空间感知、眼动追踪、手部追踪、摄像头等敏感功能,必须在Info.plist里说明用途,并且在App Store的隐私标签里如实填写。

第四,审核。visionOS应用的审核比iOS更严格,特别是涉及空间感知、沉浸式体验、隐私数据的应用。要确保应用符合Apple的设计指南和审核要求,避免被拒。

学习资源

最后,推荐一些visionOS开发的学习资源。

第一,Apple官方文档。Apple的开发者网站有完整的visionOS开发文档,包括入门指南、API参考、设计指南、示例代码。这是最权威、最全面的学习资源。

第二,WWDC视频。每年的WWDC都会有很多visionOS相关的session,从入门到高级都有。视频可以在Apple开发者网站或者YouTube上看。

第三,示例代码。Apple提供了很多visionOS的示例代码项目,涵盖了窗口、体积、沉浸式空间、手势、空间音频等各个方面。下载下来运行、修改、学习,是最好的学习方式之一。

第四,社区和论坛。Reddit的r/VisionOS、Apple开发者论坛、Discord的visionOS开发社区,都是交流和求助的好地方。遇到问题可以在这些地方搜索或提问。

第五,动手实践。学visionOS最好的方式就是动手做。从简单的窗口应用开始,逐步尝试体积、沉浸式空间、空间交互等功能,在实践中学习和成长。

写在最后

visionOS是一个全新的、充满可能性的平台。它把数字内容和真实世界融合在一起,创造了一种全新的计算体验。作为开发者,能在这个平台早期参与进来,是一件很幸运的事情。

这篇文章介绍了visionOS开发的完整配置流程,从环境搭建、基础配置、中级功能到高级特性,希望能给想入门的朋友一个清晰的路线图。当然,visionOS的功能远不止这些,还有很多细节和技巧需要在实际开发中探索。

如果你对空间计算感兴趣,想在visionOS平台上做一些有趣的东西,那就开始吧。现在正是visionOS开发的早期,机会很多,先发优势很明显。

愿我们都能在这个新的平台上,创造出令人惊叹的应用。