View in English

  • Apple 开发者
    • 入门汇总

    探索“入门汇总”

    • 概览
    • 学习
    • Apple Developer Program

    及时了解最新动态

    • 最新动态
    • 开发者你好
    • 平台

    探索“平台”

    • Apple 平台
    • iOS
    • iPadOS
    • macOS
    • Apple tvOS
    • visionOS
    • watchOS
    • App Store

    精选

    • 设计
    • 分发
    • 游戏
    • 配件
    • 网页
    • Home
    • CarPlay 车载
    • 技术

    探索“技术”

    • 概览
    • Xcode
    • Swift
    • SwiftUI

    精选

    • 辅助功能
    • App Intents
    • Apple 智能
    • 游戏
    • 机器学习与 AI
    • 安全性
    • Xcode Cloud
    • 社区

    探索“社区”

    • 概览
    • “与 Apple 会面交流”活动
    • 社区主导的活动
    • 开发者论坛
    • 开源

    精选

    • WWDC
    • Swift Student Challenge
    • 开发者故事
    • App Store 大奖
    • Apple 设计大奖
    • Apple Developer Centers
    • 文档

    探索“文档”

    • 文档库
    • 技术概述
    • 示例代码
    • 《人机界面指南》
    • 视频

    发布说明

    • 精选更新
    • iOS
    • iPadOS
    • macOS
    • watchOS
    • visionOS
    • Apple tvOS
    • Xcode
    • 下载

    探索“下载”

    • 所有下载
    • 操作系统
    • 应用程序
    • 设计资源

    精选

    • Xcode
    • TestFlight
    • 字体
    • SF Symbols
    • Icon Composer
    • 支持

    探索“支持”

    • 概览
    • 帮助指南
    • 开发者论坛
    • “反馈助理”
    • 联系我们

    精选

    • 《开发者账户帮助》
    • 《App 审核指南》
    • 《App Store Connect 帮助》
    • 即将实行的要求
    • 协议和准则
    • 系统状态
  • 快速链接

    • 活动
    • 新闻
    • 论坛
    • 示例代码
    • 视频
 

视频

打开菜单 关闭菜单
  • 专题
  • 所有视频
  • 关于

更多视频

  • 简介
  • 概要
  • 代码
  • 将 SwiftUI 与 AppKit 和 UIKit 搭配使用

    了解如何在现有的 AppKit 或 UIKit App 中逐步采用 SwiftUI。我们将介绍如何使用 Observation 框架自动更新视图,将 SwiftUI 组件整合到现有的视图层次结构中,并将手势识别器引入 SwiftUI。我们还将探索如何向你的 App 添加完整的 SwiftUI 场景,同时不改变整体架构。

    章节

    • 0:00 - Introduction
    • 2:33 - Observation in AppKit
    • 5:41 - Hosting SwiftUI in AppKit
    • 7:48 - AppKit gestures in SwiftUI
    • 9:16 - SwiftUI in the main menu
    • 11:30 - SwiftUI scenes in AppKit
    • 13:04 - Next steps

    资源

      • 高清视频
      • 标清视频

    相关视频

    WWDC26

    • 使用 SwiftUI 构建高级图形效果

    WWDC25

    • UIKit 的新功能

    WWDC22

    • 为您的 SwiftUI App 添加多个窗口
    • 将 SwiftUI 与 AppKit 搭配使用
    • 将 SwiftUI 与 UIKit 搭配使用

    WWDC21

    • 向你的 SwiftUI app 添加丰富图形
  • 搜索此视频…
    • 3:39 - Observation in AppKit

      // Observation in AppKit
      
      import Observation
      
      @Observable @MainActor
      final class ColorModel {
          var hue: Double = 0.6
          var saturation: Double = 1.0
          var brightness: Double = 1.0
      }
    • 6:28 - Circular color picker

      // Circular color picker
      
      import SwiftUI
      import Observation
      
      @Observable @MainActor
      final class ColorModel {
          var hue: Double = 0.6
          var saturation: Double = 1.0
          var brightness: Double = 1.0
      }
      
      // MARK: - Picker View
      
      @Animatable
      struct HSBColorPicker: View {
          var hue: Double
          var saturation: Double
          var brightness: Double
          @AnimatableIgnored var model: ColorModel
      
          init(model: ColorModel) {
              self.model = model
              self.hue = model.hue
              self.saturation = model.saturation
              self.brightness = model.brightness
          }
      
          var body: some View {
              Canvas { context, size in
                  let metrics = PickerMetrics(size: size)
                  drawPicker(in: &context, metrics: metrics, hue: hue, saturation: saturation, brightness: brightness)
              }
              .contentShape(Circle())
              .modifier(ColorPickerDragGesture(model: model))
              .aspectRatio(1, contentMode: .fit)
          }
      }
      
      // MARK: - Drag Gesture
      
      private struct ColorPickerDragGesture: ViewModifier {
          var model: ColorModel
      
          private enum Ring { case hue, saturation, brightness }
          @State private var draggedRing: Ring?
      
          func body(content: Content) -> some View {
              GeometryReader { proxy in
                  content.gesture(
                      DragGesture(minimumDistance: 0, coordinateSpace: .local)
                          .onChanged { onDrag(to: $0.location, size: proxy.size) }
                          .onEnded { _ in draggedRing = nil }
                  )
              }
          }
      
          private func onDrag(to location: CGPoint, size: CGSize) {
              let metrics = PickerMetrics(size: size)
              let point = CGPoint(x: location.x - metrics.mid.x, y: location.y - metrics.mid.y)
              if draggedRing == nil {
                  let distance = hypot(point.x, point.y)
                  if distance >= metrics.radius - metrics.ringWidth - metrics.gap / 2 {
                      draggedRing = .hue
                  } else if distance >= metrics.radius - metrics.ringWidth * 2 - metrics.gap {
                      draggedRing = point.x > 0 ? .brightness : .saturation
                  }
              }
              switch draggedRing {
              case .hue: model.hue = (angle0To2Pi(point) / (2 * .pi) + 0.25).truncatingRemainder(dividingBy: 1)
              case .saturation: model.saturation = leftSemicircleValue(point)
              case .brightness: model.brightness = 1 - rightSemicircleValue(point)
              case nil: break
              }
          }
      }
      
      // MARK: - Metrics
      
      struct PickerMetrics {
          let mid: CGPoint
          let radius: CGFloat
          let ringWidth: CGFloat
          let gap: CGFloat = 8
      
          init(size: CGSize) {
              let border: CGFloat = 1 // reserve room so the outer ring's stroke isn't clipped
              mid = CGPoint(x: size.width / 2, y: size.height / 2)
              radius = (min(size.width, size.height) - 2 * border) / 2
              ringWidth = radius / 3
          }
      
          var diameter: CGFloat { radius * 2 }
          var innerRadius: CGFloat { (diameter - 2 * ringWidth - gap) / 2 }
          var centerRadius: CGFloat { radius - 2 * ringWidth - gap }
      }
      
      // MARK: - Geometry Helpers
      
      func angle0To2Pi(_ point: CGPoint) -> CGFloat {
          let a = atan2(point.y, point.x)
          return a >= 0 ? a : a + 2 * .pi
      }
      
      func rightSemicircleValue(_ point: CGPoint) -> CGFloat {
          let angle = atan2(point.y, point.x)
          return point.x >= 0 ? (angle + .pi / 2) / .pi : (point.y >= 0 ? 1 : 0)
      }
      
      func leftSemicircleValue(_ point: CGPoint) -> CGFloat {
          guard point.x <= 0 else { return point.y >= 0 ? 1 : 0 }
          return (atan2(point.y, -point.x) + .pi / 2) / .pi
      }
      
      private extension Path {
          /// A circle whose stroke of `lineWidth` lands inside `radius`.
          init(ring radius: CGFloat, center: CGPoint, lineWidth: CGFloat) {
              let inset = radius - lineWidth / 2
              self.init(ellipseIn: CGRect(x: center.x - inset, y: center.y - inset, width: inset * 2, height: inset * 2))
          }
      }
      
      // MARK: - Drawing
      
      private func drawPicker(in context: inout GraphicsContext, metrics: PickerMetrics, hue: Double, saturation: Double, brightness: Double) {
          drawHueRing(in: &context, metrics: metrics, hue: hue, saturation: saturation, brightness: brightness)
          drawValueRings(in: &context, metrics: metrics, hue: hue, saturation: saturation, brightness: brightness)
          drawCenter(in: &context, metrics: metrics, hue: hue, saturation: saturation, brightness: brightness)
      }
      
      private func drawHueRing(in context: inout GraphicsContext, metrics: PickerMetrics, hue: Double, saturation: Double, brightness: Double) {
          let ring = Path(ring: metrics.radius, center: metrics.mid, lineWidth: metrics.ringWidth)
          // A custom metal shader would be work great here as well
          let colors = stride(from: 0.0, through: 1, by: 1.0 / 64).map { Color(hue: $0, saturation: saturation, brightness: brightness) }
          context.stroke(ring, with: .conicGradient(Gradient(colors: colors), center: metrics.mid, angle: .degrees(-90)), lineWidth: metrics.ringWidth)
          context.stroke(ring.strokedPath(StrokeStyle(lineWidth: metrics.ringWidth)), with: .color(.black), lineWidth: 1)
          // Tick marks are left as a fun exercise for the reader.
          drawKnob(in: &context, metrics: metrics, radius: metrics.radius, rotation: 2 * .pi * hue + .pi)
      }
      
      private func drawValueRings(in context: inout GraphicsContext, metrics: PickerMetrics, hue: Double, saturation: Double, brightness: Double) {
          drawSemicircle(in: &context, metrics: metrics, start: .degrees(90), conicAngle: .degrees(0), stops: (0...1).map {
              Gradient.Stop(color: Color(hue: hue, saturation: 1 - Double($0), brightness: brightness), location: 0.25 + Double($0) * 0.5)
          })
          drawSemicircle(in: &context, metrics: metrics, start: .degrees(270), conicAngle: .degrees(180), stops: (0...1).map {
              Gradient.Stop(color: Color(hue: hue, saturation: saturation, brightness: 1 - Double($0)), location: 0.25 + Double($0) * 0.5)
          })
          drawKnob(in: &context, metrics: metrics, radius: metrics.innerRadius, rotation: .pi * (1 - saturation))
          drawKnob(in: &context, metrics: metrics, radius: metrics.innerRadius, rotation: .pi * (1 - brightness) + .pi)
      }
      
      private func drawSemicircle(in context: inout GraphicsContext, metrics: PickerMetrics, start: Angle, conicAngle: Angle, stops: [Gradient.Stop]) {
          var path = Path()
          path.addArc(center: metrics.mid, radius: metrics.innerRadius - metrics.ringWidth / 2, startAngle: start, endAngle: start + .degrees(180), clockwise: false)
          let band = path.strokedPath(StrokeStyle(lineWidth: metrics.ringWidth))
          context.fill(band, with: .conicGradient(Gradient(stops: stops), center: metrics.mid, angle: conicAngle))
          context.stroke(band, with: .color(.black), lineWidth: 1)
          // Tick marks are left as a fun exercise for the reader.
      }
      
      private func drawCenter(in context: inout GraphicsContext, metrics: PickerMetrics, hue: Double, saturation: Double, brightness: Double) {
          let r = metrics.centerRadius
          let disc = Path(ellipseIn: CGRect(x: metrics.mid.x - r, y: metrics.mid.y - r, width: r * 2, height: r * 2))
          context.fill(disc, with: .color(Color(hue: hue, saturation: saturation, brightness: brightness)))
          context.stroke(disc, with: .color(.black))
      }
      
      private func drawKnob(in context: inout GraphicsContext, metrics: PickerMetrics, radius: CGFloat, rotation: CGFloat) {
          let lineWidth: CGFloat = 5
          let inset: CGFloat = 3 + lineWidth / 2
          var path = Path()
          path.move(to: CGPoint(x: 0, y: radius - metrics.ringWidth + inset))
          path.addLine(to: CGPoint(x: 0, y: radius - inset))
          path = path.applying(CGAffineTransform(rotationAngle: rotation))
          path = path.applying(CGAffineTransform(translationX: metrics.mid.x, y: metrics.mid.y))
          context.stroke(path, with: .color(.black.opacity(0.8)), style: StrokeStyle(lineWidth: lineWidth + 1, lineCap: .round))
          context.stroke(path, with: .color(.white), style: StrokeStyle(lineWidth: lineWidth, lineCap: .round))
      }
      
      #Preview {
          @Previewable @State var model = ColorModel()
          HSBColorPicker(model: model)
              .frame(width: 320, height: 320)
              .padding()
      }
    • 7:21 - Hosting SwiftUI in AppKit

      // Hosting SwiftUI in AppKit
      
      NSHostingView(
          rootView: HSBColorPicker(model: model)
      )
    • 8:14 - Mix NSGestureRecognizer with SwiftUI

      // Mix NSGestureRecognizer with SwiftUI
      
      import SwiftUI
      import AppKit
      
      @Observable @MainActor
      final class ColorModel {
          var hue: Double = 0.6
          var saturation: Double = 1.0
          var brightness: Double = 1.0
      }
      
      struct ForceClickReset: NSGestureRecognizerRepresentable {
          var model: ColorModel
      
          func makeNSGestureRecognizer(context: Context) -> ForceClickGestureRecognizer {
              ForceClickGestureRecognizer()
          }
      
          func handleNSGestureRecognizerAction(_ recognizer: ForceClickGestureRecognizer, context: Context) {
              withAnimation {
                  model.saturation = 1
                  model.brightness = 1
              }
          }
      }
      
      final class ForceClickGestureRecognizer: NSGestureRecognizer {
          private var didActivate = false
      
          override func pressureChange(with event: NSEvent) {
              if event.stage >= 2 && !didActivate {
                  didActivate = true
                  state = .ended
              }
          }
      
          override func mouseDown(with event: NSEvent) {
              didActivate = false
              state = .possible
          }
      
          override func mouseUp(with event: NSEvent) {
              didActivate = false
              state = .possible
          }
      }
    • 9:42 - Adding ColorMenu to the Main Menu

      // Adding ColorMenu to the Main Menu
      
      import AppKit
      import SwiftUI
      import Observation
      
      @Observable @MainActor
      final class ColorModel {
          var hue: Double = 0.6
          var saturation: Double = 1.0
          var brightness: Double = 1.0
      }
      
      // Menu definition in SwiftUI.
      struct ColorMenu: View {
          var model: ColorModel
      
          private static let hues: [(name: String, hue: Double)] = [
              ("Red", 0), ("Yellow", 0.17), ("Green", 0.33), ("Cyan", 0.5), ("Blue", 0.67), ("Purple", 0.83),
          ]
      
          var body: some View {
              Button("Full Intensity") {
                  withAnimation {
                      model.saturation = 1
                      model.brightness = 1
                  }
              }
              .keyboardShortcut(.upArrow, modifiers: [.command, .shift])
      
              Button("Blackout") {
                  withAnimation {
                      model.brightness = 0
                  }
              }
              .keyboardShortcut(.downArrow, modifiers: [.command, .shift])
      
              Divider()
      
              Button("Brighten") {
                  withAnimation {
                      model.brightness = min(1, model.brightness + 0.1)
                  }
              }
              .keyboardShortcut(.upArrow, modifiers: .command)
      
              Button("Dim") {
                  withAnimation {
                      model.brightness = max(0, model.brightness - 0.1)
                  }
              }
              .keyboardShortcut(.downArrow, modifiers: .command)
      
              Divider()
      
              Picker("Color", selection: Bindable(model).hue) {
                  ForEach(Self.hues, id: \.hue) { entry in
                      Label(entry.name, systemImage: "circle.fill")
                          .tint(Color(hue: entry.hue, saturation: 1, brightness: 1))
                          .tag(entry.hue)
                  }
              }
              .pickerStyle(.palette)
          }
      }
      
      @MainActor
      class AppDelegate: NSObject, NSApplicationDelegate {
          let colorModel = ColorModel()
      
          func setupMainMenu() {
              let mainMenu = NSMenu()
      
              let colorMenu = NSHostingMenu(rootView: ColorMenu(model: colorModel))
              colorMenu.title = "Color"
      
              let colorMenuItem = NSMenuItem()
              colorMenuItem.submenu = colorMenu
              mainMenu.addItem(colorMenuItem)
          }
      }
      
      #Preview {
          Menu("Color") {
              ColorMenu(model: ColorModel())
      
          }.padding()
      }
    • 11:36 - Adding SwiftUI scenes dynamically

      // Adding SwiftUI scenes dynamically
      
      import AppKit
      import SwiftUI
      import Observation
      
      @MainActor
      class AppDelegate: NSObject, NSApplicationDelegate {
          let model = AppModel()
          var openSettingsAction: (() -> Void)?
      
          func applicationWillFinishLaunching(_ notification: Notification) {
              let scenes = NSHostingSceneRepresentation {
                  LightMenuBarExtra(appModel: model)
                  LightSettings(appModel: model)
              }
              NSApplication.shared.addSceneRepresentation(scenes)
              openSettingsAction = {
                  scenes.environment.openSettings()
              }
          }
      
          @IBAction func openSettings(_ sender: Any?) {
              openSettingsAction?()
          }
      }
      
      @Observable @MainActor
      final class ColorModel {
          var hue: Double = 0.6
          var saturation: Double = 1.0
          var brightness: Double = 1.0
      
          var color: Color {
              Color(hue: hue, saturation: saturation, brightness: brightness)
          }
      }
      
      @Observable @MainActor
      final class AppModel {
          var showMenuBarExtra: Bool = true
      
          var colorModel = ColorModel()
      
          var startUniverse: Int = 1
          var numberOfPixels: Int = 50
      
          var maxBrightness: Double = 1.0
          var isConnected: Bool = false
      }
      
      struct LightMenuBarExtra: Scene {
          var appModel: AppModel
      
          var body: some Scene {
              MenuBarExtra("Light Mix", systemImage: "lightbulb.fill", isInserted: Bindable(appModel).showMenuBarExtra) {
                  MenuBarContent(appModel: appModel)
              }
              .menuBarExtraStyle(.window)
          }
      }
      
      
      struct MenuBarContent: View {
          @Bindable var appModel: AppModel
      
          var body: some View {
              // TODO: Use HSBColorPicker
              VStack {
                  RoundedRectangle(cornerRadius: 10)
                      .fill(appModel.colorModel.color)
                      .frame(height: 80)
                      .overlay(RoundedRectangle(cornerRadius: 10).stroke(.black.opacity(0.1)))
      
                  LabeledContent("Brightness") {
                      Slider(value: $appModel.colorModel.brightness)
                          .frame(width: 140)
                  }
              }
              .padding()
              .frame(width: 280)
          }
      }
      
      struct LightSettings: Scene {
          var appModel: AppModel
      
          var body: some Scene {
              Settings {
                  SettingsView(appModel: appModel)
              }
          }
      }
      
      struct SettingsView: View {
          var appModel: AppModel
      
          var body: some View {
              TabView {
                  Tab("General", systemImage: "gearshape") {
                      GeneralTab(appModel: appModel)
                  }
                  Tab("Output", systemImage: "antenna.radiowaves.left.and.right") {
                      OutputTab(appModel: appModel)
                  }
                  Tab("About", systemImage: "info.circle") {
                      AboutTab()
                  }
              }
              .formStyle(.grouped)
              .scrollDisabled(true)
              .frame(width: 460)
              .fixedSize(horizontal: false, vertical: true)
          }
      }
      
      struct GeneralTab: View {
          @Bindable var appModel: AppModel
      
          var body: some View {
              Form {
                  Section("Appearance") {
                      Toggle("Show in Menu Bar", isOn: $appModel.showMenuBarExtra)
                  }
                  Section("DMX Configuration") {
                      LabeledContent("Start Universe") {
                          TextField("", value: $appModel.startUniverse, format: .number)
                              .textFieldStyle(.roundedBorder)
                              .frame(width: 80)
                      }
                      LabeledContent("Number of Pixels") {
                          TextField("", value: $appModel.numberOfPixels, format: .number)
                              .textFieldStyle(.roundedBorder)
                              .frame(width: 80)
                      }
                  }
              }
          }
      }
      
      struct OutputTab: View {
          @Bindable var appModel: AppModel
      
          var body: some View {
              Form {
                  Section("Output") {
                      LabeledContent("Max Brightness") {
                          HStack {
                              Slider(value: $appModel.maxBrightness, in: 0...1)
                              Text("\(Int((appModel.maxBrightness * 100).rounded()))%")
                                  .monospacedDigit()
                                  .foregroundStyle(.secondary)
                                  .frame(width: 40, alignment: .trailing)
                          }
                      }
                  }
              }
          }
      }
      
      struct AboutTab: View {
          var body: some View {
              VStack(spacing: 16) {
                  Image(systemName: "lightbulb.fill")
                      .font(.system(size: 48))
                      .foregroundStyle(.yellow.gradient)
      
                  Text("Light Mix")
                      .font(.title2.bold())
      
                  Text("WWDC26 — Bring SwiftUI to your AppKit and UIKit App")
                      .multilineTextAlignment(.center)
                      .foregroundStyle(.secondary)
              }
          }
      }
      
      #Preview("Menu Bar") {
          MenuBarContent(appModel: AppModel())
      }
      
      #Preview("Settings") {
          SettingsView(appModel: AppModel())
      }
    • 0:00 - Introduction
    • How SwiftUI is designed to work alongside existing AppKit and UIKit apps — already used in Logic Pro plugins, Xcode's Coding Assistant, and even AppKit controls like NSSlider, NSSwitch, and NSSegmentedControl. Previews the agenda using a sample lighting-control app: Observation in AppKit, hosting SwiftUI in AppKit, AppKit gestures in SwiftUI, SwiftUI in the main menu, and SwiftUI scenes in AppKit.

    • 2:33 - Observation in AppKit
    • Replace manual needsDisplay invalidation with automatic updates by adopting @Observable on your model. AppKit (and UIKit) automatically track property reads in draw, updateConstraints, layout, updateLayer, and their NSViewController equivalents — so dependent views redraw when the model changes. Back-deployable to macOS 15 / iOS 18 via NSObservationTrackingEnabled / UIObservationTrackingEnabled, and on by default with the 2026 releases.

    • 5:41 - Hosting SwiftUI in AppKit
    • When a new feature would require very different drawing or interaction code, it's a good moment to move to SwiftUI. Reimplement the color picker as a SwiftUI Canvas — an immediate-mode drawing API similar to drawRect, with withCGContext for reusing existing CoreGraphics code — then embed the SwiftUI view in the existing AppKit hierarchy with NSHostingView.

    • 7:48 - AppKit gestures in SwiftUI
    • Reuse an existing NSGestureRecognizer subclass directly in a SwiftUI view via the new NSGestureRecognizerRepresentable protocol. Implement makeNSGestureRecognizer and handleNSGestureRecognizerAction, then attach it with the standard .gesture modifier — shown adding a Force Click to reset brightness and saturation alongside an existing drag gesture.

    • 9:16 - SwiftUI in the main menu
    • Build a menu in SwiftUI as a regular View — Buttons with actions, keyboard shortcuts, and a palette-style Picker — then add it to the AppKit main menu using NSHostingMenu (an NSMenu subclass) wrapped in an NSMenuItem. Ensures features like the Force Click reset are also available to people on input devices that don't support force gestures.

    • 11:30 - SwiftUI scenes in AppKit
    • Use NSHostingSceneRepresentation to add complete SwiftUI scenes to an app with the AppKit lifecycle. Add a MenuBarExtra for quick light controls, and a Settings scene with a Toggle that inserts or removes the MenuBarExtra dynamically — all from your existing NSApplicationDelegate.

    • 13:04 - Next steps
    • Start using @Observable to keep models and NSViews in sync, consider SwiftUI for new views, reuse existing gestures via the representable protocol, and use SwiftUI for new scenes. There's no expectation that an app needs to be entirely SwiftUI to take advantage of it.

Developer Footer

  • 视频
  • WWDC26
  • 将 SwiftUI 与 AppKit 和 UIKit 搭配使用
  • 打开菜单 关闭菜单
    • iOS
    • iPadOS
    • macOS
    • Apple tvOS
    • visionOS
    • watchOS
    打开菜单 关闭菜单
    • Swift
    • SwiftUI
    • Swift Playground
    • TestFlight
    • Xcode
    • Xcode Cloud
    • SF Symbols
    打开菜单 关闭菜单
    • 辅助功能
    • 配件
    • Apple 智能
    • App 扩展
    • App Store
    • 音频与视频 (英文)
    • 增强现实
    • 设计
    • 分发
    • 教育
    • 字体 (英文)
    • 游戏
    • 健康与健身
    • App 内购买项目
    • 本地化
    • 地图与位置
    • 机器学习与 AI
    • 开源资源 (英文)
    • 安全性
    • Safari 浏览器与网页 (英文)
    打开菜单 关闭菜单
    • 完整文档 (英文)
    • 部分主题文档 (简体中文)
    • 教程
    • 下载
    • 论坛 (英文)
    • 视频
    打开菜单 关闭菜单
    • 支持文档
    • 联系我们
    • 错误报告
    • 系统状态 (英文)
    打开菜单 关闭菜单
    • Apple 开发者
    • App Store Connect
    • 证书、标识符和描述文件 (英文)
    • 反馈助理
    打开菜单 关闭菜单
    • Apple Developer Program
    • Apple Developer Enterprise Program
    • App Store Small Business Program
    • MFi Program (英文)
    • Mini Apps Partner Program
    • News Partner Program (英文)
    • Video Partner Program (英文)
    • 安全赏金计划 (英文)
    • Security Research Device Program (英文)
    打开菜单 关闭菜单
    • 与 Apple 会面交流
    • Apple Developer Center
    • App Store 大奖 (英文)
    • Apple 设计大奖
    • Apple Developer Academies (英文)
    • WWDC
    阅读最近新闻。
    获取 Apple Developer App。
    版权所有 © 2026 Apple Inc. 保留所有权利。
    使用条款 隐私政策 协议和准则