View in English

  • 打开菜单 关闭菜单
  • Apple Developer
搜索
关闭搜索
  • Apple Developer
  • 新闻
  • 探索
  • 设计
  • 开发
  • 分发
  • 支持
  • 账户
在“”范围内搜索。

快捷链接

5 快捷链接

视频

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

返回 WWDC24

大多数浏览器和
Developer App 均支持流媒体播放。

  • 简介
  • 转写文稿
  • 代码
  • 探索 Swift on Server 生态系统

    Swift 这种语言非常适合用来编写服务器端应用程序代码,而且为 Apple 各款云端产品的关键服务提供了强大支持。我们将探索相关工具、深入研究 Swift 服务器软件包生态系统,还将展示如何与数据库交互,以及为应用程序增加可观测性。

    章节

    • 0:00 - Introduction
    • 0:13 - Agenda
    • 0:27 - Meet Swift on Server
    • 2:30 - Build a service
    • 3:46 - Swift OpenAPI generator
    • 5:42 - Database drivers
    • 10:53 - Observability
    • 15:19 - Explore the ecosystem
    • 16:12 - Wrap up

    资源

    • Forum: Programming Languages
    • Swift on Server
    • Swift Package Ecosystem
    • Swift Server Workgroup
      • 高清视频
      • 标清视频

    相关视频

    WWDC23

    • 认识 Swift OpenAPI Generator
    • 超越结构化并发的基础
  • 搜索此视频…

    大家好 我叫 Franz 来自 Apple Swift on Server 团队 今天 我们将探讨 Swift on Server 生态系统 首先 我们将讨论 Swift 为什么是 开发服务器应用程序的绝佳语言 然后 我们将使用生态系统中的 一些流行软件包来构建一项服务

    最后 我们将探讨 生态系统的运作方式 以及从哪里了解更多信息

    首先 我们来了解 Swift 为什么非常适合 进行服务器应用程序开发

    Swift 采用自动引用计数 而不是垃圾回收 因此可让你 实现类似 C 语言的性能 同时占用较少的内存 这使得 Swift 非常适合 那些需要可预测资源消耗 和快速启动时间的 现代云服务

    Swift 是一种表现力强 且安全的语言 在编译时可消除一系列错误 让开发者编写出强大且 可靠的分布式系统 强类型、可选类型和 内存安全等特性 使 Swift 服务不易出现崩溃 和安全漏洞

    云服务经常需要处理 高并发的工作负载 Swift 一流的并发功能 让开发者能够编写 可缩放且响应迅速的服务器应用程序 同时消除数据争用导致的常见错误

    所有这些特性使 Swift 成为 编写服务器应用程序的绝佳选择 事实上 Swift 为 iCloud 钥匙串、 “照片”和“备忘录”等 Apple 云服务的许多 关键功能提供支持 其他用例包括 App Store 处理管道 和同播共享文件共享 最后 我们全新的 Private Cloud Compute 服务 是使用 Swift on Server 构建的

    在 Apple 的各项服务中 使用 Swift on Server 的 应用程序每秒 可处理数百万个请求

    在 Apple 平台之外 Server 生态系统 是 Swift 的最早用户之一 事实上 Swift Server 工作组 成立于 2016 年 比 Swift 实现开源 只晚了一年时间 这使它成为历史最悠久的工作组

    这个工作组由 使用 Swift on Server 的 成员公司以及生态系统的 个人贡献者组成 致力于推广使用 Swift 来开发和部署服务器应用程序 这个工作组的职责包括 定义并优先完成满足 服务器社区需求的工作 运行软件包孵化流程 以减少重复工作 提高兼容性并推广最佳实践

    工作组还将服务器生态系统的反馈 传达给 Swift 项目的其他小组 现在 让我们使用 服务器生态系统中的 一些流行软件包来 构建一项服务 我和我的同事今年 计划参加很多活动 为确保有条不紊 我们想实现一项活动服务 用于追踪谁参加哪项活动 这个服务应支持两项操作 一是列出所有活动 以显示谁计划参加什么活动 既然我不能错过慕尼黑啤酒节 我们就需要另一项操作 来创建新活动

    要处理 Swift 软件包 你可以使用不同的编辑器 如 Xcode、VS Code、Neovim 或任何其他支持语言 服务器协议的编辑器 在今天的演示中 我们将使用 VS Code 来处理软件包 在演示过程中 我们将使用 VS Code 底部的内置终端 来查看服务的输出 并向服务发送请求 我已经准备了一个软件包 供我们开始实现活动服务 我们来看看吧

    这个软件包依赖于 OpenAPI 生成器 并使用 Vapor 作为 OpenAPI 的服务器传输

    软件包有两个目标

    一个是 EventAPI 目标 这个目标已配置 OpenAPIGenerator 插件 另一个目标

    是 EventService executableTarget 这个目标包含我们服务的实现

    通过 Swift OpenAPI Generator 我们可以用 YAML 记录服务 并为服务器和客户端生成代码 如果你是新手或想查看 OpenAPI 请观看去年的讲座 “认识 Swift OpenAPI Generator” 我们来看看 OpenAPI 文档

    这个文档定义了我们活动 路径中的两项操作

    第一项操作是一个名为 listEvents 的 get 方法

    这个操作会返回一个包含 活动数组的成功响应

    第二项操作是一个名为 createEvent 的 post 方法

    这个操作会接收活动的 JSON 主体

    并根据创建是否成功 返回 201 或 400 状态代码

    我们的服务包含主要入口点

    首先创建一个 Vapor 应用程序

    然后 在应用程序中创建 OpenAPI VaporTransport

    接下来 创建一个服务实例 并在传输系统上注册

    最后 执行 Vapor 应用程序 这将启动 HTTP 服务器 并监听传入连接

    我们的服务还实现 生成的 APIProtocol

    listEvents 方法 返回一个硬编码的活动数组

    createEvent 方法 目前返回未实现的状态代码

    让我们继续启动我们的服务

    这将构建我们的服务 并为它附加调试器 在终端底部 可以看到服务器已启动

    现在 可以在另一个终端中 使用 curl 查询我们的服务 从而列出所有活动

    很好 我们的服务返回了一个 JSON 数组 其中包含硬编码的活动列表

    不过 我们希望动态添加新活动 并将这些活动持久保存在数据库中 因此让我们来看看数据库驱动程序 开源生态系统中有许多 不同的数据库驱动程序 如 PostgreSQL、MySQL、 Cassandra、MongoDB 等

    今天 我们将使用 Postgres 数据库进行持久化 PostgresNIO 是 Postgres 的 开源数据库驱动程序 由 Vapor 和 Apple 维护 PostgresNIO 1.21 新增了 PostgresClient PostgresClient 提供 一个全新的异步接口 并随附一个利用结构化并发 功能的内置连接池 从而使它能够抵御 数据库间歇性联网故障 此外 连接池通过将查询分配到 多个连接并预热连接来提高吞吐量 从而加快查询执行速度

    让我们继续使用 PostgresNIO 将 EventService 连接到数据库

    首先 要在软件包中添加 PostgresNIO 的依赖项 并在服务中导入这个依赖项 然后 在 listEvents 方法中 使用 PostgresClient 来 查询数据库 最后 我们将实现 createEvent 方法 把新活动插入数据库 首先 让我们在软件包清单中 添加 PostgresNIO 的 依赖项

    然后 我们可以为 EventService 目标添加依赖项

    现在 我们可以在服务中 导入 PostgresNIO

    接下来 要在服务中添加一个 PostgresClient 属性

    我们将使用客户端 在 listEvents 方法中查询数据库

    查询方法会返回 行的 AsyncSequence 为替换硬编码的活动列表 我们将遍历行 解码字段 并为每一行创建一项活动

    查询方法返回的 AsyncSequence 将自动从数据库中预取行 以提升性能

    要再次运行我们的服务 必须创建一个 PostgresClient 并将它传递给我们的服务

    首先 我们创建一个 PostgresClient 以连接到 我已经在本地启动的数据库

    接下来 要把 PostgresClient 传给我们的服务

    要启动客户端 需要调用它的运行方法 这个方法将接管当前任务 直到任务完成 由于要同时运行 Vapor 应用程序 和 PostgresClient 因此我们将使用一个任务组 我们将创建一个丢弃任务组 并添加一个运行 PostgresClient 的子任务

    然后 将 Vapor 应用程序执行 移到一个单独的子任务中

    让我们再次运行服务

    重启按钮将停止当前进程 重建服务并再次启动

    底部的终端显示它正在运行 让我们再次列出所有活动

    数据库似乎是空的 要在数据库中添加新活动 接下来要实现 createEvent 方法

    首先 必须切换输入 并提取 JSON 活动

    然后 查询数据库以插入新活动

    最后 必须返回一个响应 以表明已创建活动

    看到这段代码 有些人可能会警觉起来 因为在其他语言中 这是 SQL 注入漏洞的常见载体 尽管这看起来像一个字符串 但它并不是字符串 而是使用 Swift 的 字符串插值功能 将字符串查询转换为 带值绑定的参数化查询 这使得它完全安全 不会受到 SQL 注入攻击 这个例子很好地证明了 Swift 在保证代码安全的同时 还致力于符合人体工程学

    我们将重启服务

    服务再次运行后 我们将使用 curl 创建两项活动

    看起来活动创建成功了 让我们再次列出所有活动 以检查数据库中 是否已存储这些活动

    很好 所有活动 都已保存在数据库中 Gus 刚刚给我发了一条信息 说他想带一个朋友来 问我能不能在他的名下 再添加一个活动条目 让我们继续 为 Gus 创建另一项活动

    尝试在 Gus 名下添加 另一个活动条目时好像出了点问题 在底部的终端中 我们可以看到 一条很长的错误信息 但是错误信息并没有告诉我们 到底是什么出了问题 我们看到的唯一信息是 操作无法完成 以及抛出的错误 属于 PSQLError 类型 PSQLError 的描述 有意省略了详细信息 以防止意外泄漏数据库信息 比如表的架构 在这种情况下 为服务添加额外的可观测性 有助于故障诊断 可观测性包括三大要素: 日志记录、指标和跟踪 日志记录可帮助你准确了解 服务的运行情况 让你在对问题进行排除诊断时 能够深入了解细节 指标可以让你一目了然地获得 服务健康状况的简要概览 日志和指标可以帮助你了解 单个服务的运行情况 而现代云系统通常是分布式 系统的集合 这时 跟踪可以帮助你了解 单个请求在系统中所采用的路径

    Swift 生态系统为这三大要素 都提供了 API 软件包 允许代码发送可观测性事件

    让我们来看看如何利用 listEvents 方法

    首先 当我们开始处理 新的 listEvents 请求时 可以使用 swift-log 发送日志 swift-log 支持结构化日志记录 可在日志信息中添加元数据 从而在对问题进行故障诊断时 提供更多的上下文

    接下来 可以从 swift-metrics 添加一个计数器 计数器在每次请求时会递增 以跟踪我们的服务 处理了多少个请求

    最后 可以添加 swift-distributed-tracing 来围绕数据库查询创建一个跨度 这有助于通过我们的系统对请求 进行端到端故障诊断 要进一步了解 Swift 中分布式跟踪的工作原理 请观看去年的讲座 “超越结构化并发的基础” 我们刚刚在 listEvents 方法中使用了 日志记录、指标和跟踪工具 我们使用的 API 与可观测性后端无关 服务创作者可自行选择 向何处发送数据 Swift on Server 生态系统 包含很多不同的后端 用于日志记录、指标 和分布式跟踪 选择后端 可通过调用三个库的引导方法 来完成 引导只能在可执行文件中进行 并应尽早完成 以确保 不会丢失可观测性事件 此外 建议首先引导 LoggingSystem 然后引导 MetricsSystem 最后引导 InstrumentationSystem 这是因为指标系统和仪表化系统 可能希望发送有关自身状态的日志

    只需几行代码 我们就能向终端发送日志 向 Prometheus 发送指标 向 Open Telemetry 发送跟踪 让我们在 createEvent 方法中 添加日志记录 来了解当尝试在 Gus 名下添加 另一项活动时 究竟哪里出现问题

    首先 必须在软件包和 EventService 目标中 添加 swift-log 作为依赖项

    然后 就可以在服务中导入 日志记录模块

    接下来 我们将捕获查询方法 抛出的错误

    如果在执行查询时出现问题 查询方法就会抛出 PSQLError

    让我们创建一个日志记录器 这样就能发送 包含 Postgres 服务器发送的 错误信息的日志事件

    接下来 提取错误信息并发送日志 PSQLError 在 serverInfo 属性中包含 出错点的详细信息

    最后 我们将返回 badRequest 响应 指出在将活动添加到 数据库时出现问题

    让我们重启服务 看看能否获得关于错误的 更多详细信息

    默认情况下 swift-log 会将日志发送到终端 这非常适合调试我们的应用程序 我们运行相同的 curl 命令 再次创建活动

    这次我们没有再遇到同样的错误 因为我们返回了 badRequest 状态代码

    因此 让我们查看一下服务日志 看看哪里出了问题

    在底部的终端可以看到日志信息 错误信息元数据字段告诉我们 错误是由于重复键违规导致的 我们的数据库表只允许姓名、 日期和参与者组合成一个条目

    添加日志帮助我们对具体问题 进行了故障诊断 我稍后会让我的同事修复这个错误

    以上只是对 Swift on Server 生态系统中 一些库的简单介绍 你可以用这些库来构建服务 还有很多库适用于各种用例 如联网、 数据库驱动程序、 可观测性、 消息流 等等 如果你希望查找更多库 请访问 swift.org 软件包部分 并探索服务器类别 你还可以使用 swift 软件包索引 查找更多服务器库

    另一个查找软件包的重要资源是 Swift Server 工作组的 孵化列表 工作组运行软件包孵化流程 来创建强大而稳定的生态系统

    孵化流程中的软件包 从 Sandbox 到 Incubating 再到 Graduated 实现成熟度级别转换

    每个级别都有与软件包的 生产就绪度和使用情况 相一致的不同要求 你可以在 swift.org 上找到 已孵化软件包的列表

    希望本讲座能激发你对 Swift on Server 生态系统的热情 我们讨论了 Swift 为何 是服务器应用程序的 绝佳语言 以及它如何为 Apple 云服务的 许多关键功能 提供助力与支持 我们还探讨了一些软件包 以及 Swift Server 工作组 如何帮助生态系统健康成长 感谢大家观看! 啤酒节上见!

    • 3:23 - EventService Package.swift

      // swift-tools-version:5.9
      import PackageDescription
      
      let package = Package(
        name: "EventService",
        platforms: [.macOS(.v14)],
        dependencies: [
          .package(
            url: "https://github.com/apple/swift-openapi-generator",
            from: "1.2.1"
          ),
          .package(
            url: "https://github.com/apple/swift-openapi-runtime",
            from: "1.4.0"
          ),
          .package(
            url: "https://github.com/vapor/vapor",
            from: "4.99.2"
          ),
          .package(
            url: "https://github.com/swift-server/swift-openapi-vapor",
            from: "1.0.1"
          ),
        ],
        targets: [
          .target(
            name: "EventAPI",
            dependencies: [
              .product(
                name: "OpenAPIRuntime",
                package: "swift-openapi-runtime"
              ),
            ],
            plugins: [
              .plugin(
                name: "OpenAPIGenerator",
                package: "swift-openapi-generator"
              )
            ]
          ),
          .executableTarget(
            name: "EventService",
            dependencies: [
              "EventAPI",
              .product(
                name: "OpenAPIRuntime",
                package: "swift-openapi-runtime"
              ),
              .product(
                name: "OpenAPIVapor",
                package: "swift-openapi-vapor"
              ),
              .product(
                name: "Vapor",
                package: "vapor"
              ),
            ]
          ),
        ]
      )
    • 4:05 - EventService openapi.yaml

      openapi: "3.1.0"
      info:
        title: "EventService"
        version: "1.0.0"
      servers:
        - url: "https://localhost:8080/api"
          description: "Example service deployment."
      paths:
        /events:
          get:
            operationId: "listEvents"
            responses:
              "200":
                description: "A success response with all events."
                content:
                  application/json:
                    schema:
                      type: "array"
                      items:
                        $ref: "#/components/schemas/Event"
          post:
            operationId: "createEvent"
            requestBody:
              description: "The event to create."
              required: true
              content:
                application/json:
                  schema:
                    $ref: '#/components/schemas/Event'
            responses:
              '201':
                description: "A success indicating the event was created."
              '400':
                description: "A failure indicating the event wasn't created."
      components:
        schemas:
          Event:
            type: "object"
            description: "An event."
            properties:
              name:
                type: "string"
                description: "The event's name."
              date:
                type: "string"
                format: "date"
                description: "The day of the event."
              attendee:
                type: "string"
                description: "The name of the person attending the event."
            required:
              - "name"
              - "date"
              - "attendee"
    • 4:35 - EventService initial implementation

      import OpenAPIRuntime
      import OpenAPIVapor
      import Vapor
      import EventAPI
      
      @main
      struct Service {
        static func main() async throws {
          let application = try await Vapor.Application.make()
          let transport = VaporTransport(routesBuilder: application)
      
          let service = Service()
          try service.registerHandlers(
            on: transport,
            serverURL: URL(string: "/api")!
          )
      
          try await application.execute()
        }
      }
      
      extension Service: APIProtocol {
        func listEvents(
          _ input: Operations.listEvents.Input
        ) async throws -> Operations.listEvents.Output {
          let events: [Components.Schemas.Event] = [
            .init(name: "Server-Side Swift Conference", date: "26.09.2024", attendee: "Gus"),
            .init(name: "Oktoberfest", date: "21.09.2024", attendee: "Werner"),
          ]
      
          return .ok(.init(body: .json(events)))
        }
      
        func createEvent(
          _ input: Operations.createEvent.Input
        ) async throws -> Operations.createEvent.Output {
          return .undocumented(statusCode: 501, .init())
        }
      }
    • 6:56 - EventService Package.swift

      // swift-tools-version:5.9
      import PackageDescription
      
      let package = Package(
        name: "EventService",
        platforms: [.macOS(.v14)],
        dependencies: [
          .package(
            url: "https://github.com/apple/swift-openapi-generator",
            from: "1.2.1"
          ),
          .package(
            url: "https://github.com/apple/swift-openapi-runtime",
            from: "1.4.0"
          ),
          .package(
            url: "https://github.com/vapor/vapor",
            from: "4.99.2"
          ),
          .package(
            url: "https://github.com/swift-server/swift-openapi-vapor",
            from: "1.0.1"
          ),
          .package(
            url: "https://github.com/vapor/postgres-nio",
            from: "1.19.1"
          ),
        ],
        targets: [
          .target(
            name: "EventAPI",
            dependencies: [
              .product(
                name: "OpenAPIRuntime",
                package: "swift-openapi-runtime"
              ),
            ],
            plugins: [
              .plugin(
                name: "OpenAPIGenerator",
                package: "swift-openapi-generator"
              )
            ]
          ),
          .executableTarget(
            name: "EventService",
            dependencies: [
              "EventAPI",
              .product(
                name: "OpenAPIRuntime",
                package: "swift-openapi-runtime"
              ),
              .product(
                name: "OpenAPIVapor",
                package: "swift-openapi-vapor"
              ),
              .product(
                name: "Vapor",
                package: "vapor"
              ),
              .product(
                  name: "PostgresNIO",
                package: "postgres-nio"
              ),
            ]
          ),
        ]
      )
    • 7:08 - Implementing the listEvents method

      import OpenAPIRuntime
      import OpenAPIVapor
      import Vapor
      import EventAPI
      import PostgresNIO
      
      @main
      struct Service {
        let postgresClient: PostgresClient
        
        static func main() async throws {
          let application = try await Vapor.Application.make()
          let transport = VaporTransport(routesBuilder: application)
      
          let postgresClient = PostgresClient(
            configuration: .init(
              host: "localhost",
              username: "postgres",
              password: nil,
              database: nil,
              tls: .disable
            )
          )
          let service = Service(postgresClient: postgresClient)
          try service.registerHandlers(
            on: transport,
            serverURL: URL(string: "/api")!
          )
      
          try await withThrowingDiscardingTaskGroup { group in
            group.addTask {
              await postgresClient.run()
            }
      
            group.addTask {
              try await application.execute()
            }
          }
        }
      }
      
      extension Service: APIProtocol {
        func listEvents(
          _ input: Operations.listEvents.Input
        ) async throws -> Operations.listEvents.Output {
          let rows = try await self.postgresClient.query("SELECT name, date, attendee FROM events")
      
          var events = [Components.Schemas.Event]()
          for try await (name, date, attendee) in rows.decode((String, String, String).self) {
            events.append(.init(name: name, date: date, attendee: attendee))
          }
      
          return .ok(.init(body: .json(events)))
        }
      
        func createEvent(
          _ input: Operations.createEvent.Input
        ) async throws -> Operations.createEvent.Output {
          return .undocumented(statusCode: 501, .init())
        }
      }
    • 9:02 - Implementing the createEvent method

      func createEvent(
        _ input: Operations.createEvent.Input
      ) async throws -> Operations.createEvent.Output {
        switch input.body {
        case .json(let event):
          try await self.postgresClient.query(
            """
            INSERT INTO events (name, date, attendee)
            VALUES (\(event.name), \(event.date), \(event.attendee))
            """
          )
          return .created(.init())
        }
      }
    • 11:34 - Instrumenting the listEvents method

      func listEvents(
        _ input: Operations.listEvents.Input
      ) async throws -> Operations.listEvents.Output {
        let logger = Logger(label: "ListEvents")
        logger.info("Handling request", metadata: ["operation": "\(Operations.listEvents.id)"])
      
        Counter(label: "list.events.counter").increment()
      
        return try await withSpan("database query") { span in
          let rows = try await postgresClient.query("SELECT name, date, attendee FROM events")
          return try await .ok(.init(body: .json(decodeEvents(rows))))
        }
      }
    • 13:14 - EventService Package.swift

      // swift-tools-version:5.9
      import PackageDescription
      
      let package = Package(
        name: "EventService",
        platforms: [.macOS(.v14)],
        dependencies: [
          .package(
            url: "https://github.com/apple/swift-openapi-generator",
            from: "1.2.1"
          ),
          .package(
            url: "https://github.com/apple/swift-openapi-runtime",
            from: "1.4.0"
          ),
          .package(
            url: "https://github.com/vapor/vapor",
            from: "4.99.2"
          ),
          .package(
            url: "https://github.com/swift-server/swift-openapi-vapor",
            from: "1.0.1"
          ),
          .package(
            url: "https://github.com/vapor/postgres-nio",
            from: "1.19.1"
          ),
          .package(
              url: "https://github.com/apple/swift-log",
              from: "1.5.4"
          ),
        ],
        targets: [
          .target(
            name: "EventAPI",
            dependencies: [
              .product(
                name: "OpenAPIRuntime",
                package: "swift-openapi-runtime"
              ),
            ],
            plugins: [
              .plugin(
                name: "OpenAPIGenerator",
                package: "swift-openapi-generator"
              )
            ]
          ),
          .executableTarget(
            name: "EventService",
            dependencies: [
              "EventAPI",
              .product(
                name: "OpenAPIRuntime",
                package: "swift-openapi-runtime"
              ),
              .product(
                name: "OpenAPIVapor",
                package: "swift-openapi-vapor"
              ),
              .product(
                name: "Vapor",
                package: "vapor"
              ),
              .product(
                  name: "PostgresNIO",
                package: "postgres-nio"
              ),
              .product(
                  name: "Logging",
                  package: "swift-log"
              ),
            ]
          ),
        ]
      )
    • 13:38 - Adding logging to the createEvent method

      func createEvent(
        _ input: Operations.createEvent.Input
      ) async throws -> Operations.createEvent.Output {
        switch input.body {
        case .json(let event):
          do {
            try await self.postgresClient.query(
              """
              INSERT INTO events (name, date, attendee)
              VALUES (\(event.name), \(event.date), \(event.attendee))
              """
            )
            return .created(.init())
          } catch let error as PSQLError {
            let logger = Logger(label: "CreateEvent")
      
            if let message = error.serverInfo?[.message] {
              logger.info(
                "Failed to create event",
                metadata: ["error.message": "\(message)"]
              )
            }
            
            return .badRequest(.init())
          }
        }
      }

Developer Footer

  • 视频
  • WWDC24
  • 探索 Swift on Server 生态系统
  • 打开菜单 关闭菜单
    • iOS
    • iPadOS
    • macOS
    • Apple tvOS
    • visionOS
    • watchOS
    打开菜单 关闭菜单
    • Swift
    • SwiftUI
    • Swift Playground
    • TestFlight
    • Xcode
    • Xcode Cloud
    • SF Symbols
    打开菜单 关闭菜单
    • 辅助功能
    • 配件
    • App 扩展
    • App Store
    • 音频与视频 (英文)
    • 增强现实
    • 设计
    • 分发
    • 教育
    • 字体 (英文)
    • 游戏
    • 健康与健身
    • App 内购买项目
    • 本地化
    • 地图与位置
    • 机器学习
    • 开源资源 (英文)
    • 安全性
    • Safari 浏览器与网页 (英文)
    打开菜单 关闭菜单
    • 完整文档 (英文)
    • 部分主题文档 (简体中文)
    • 教程
    • 下载 (英文)
    • 论坛 (英文)
    • 视频
    打开菜单 关闭菜单
    • 支持文档
    • 联系我们
    • 错误报告
    • 系统状态 (英文)
    打开菜单 关闭菜单
    • Apple 开发者
    • App Store Connect
    • 证书、标识符和描述文件 (英文)
    • 反馈助理
    打开菜单 关闭菜单
    • Apple Developer Program
    • Apple Developer Enterprise Program
    • App Store Small Business Program
    • MFi 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。
    版权所有 © 2025 Apple Inc. 保留所有权利。
    使用条款 隐私政策 协议和准则