View in English

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

快捷链接

5 快捷链接

视频

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

更多视频

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

  • 简介
  • 概要
  • 转写文稿
  • 代码
  • 借助 Wi-Fi Aware 增强设备连接性能

    了解如何使用 Wi-Fi Aware 建立对等网络连接。我们还将介绍如何以带宽更高、延迟更低的网络连接性能实时共享视频、传输大文件,以及操控配件。此外,你将了解如何借助 DeviceDiscoveryUI、AccessorySetupKit 和 Network 框架,在自己的 App 中使用 Wi-Fi Aware。

    章节

    • 0:00 - Introduction
    • 1:01 - Overview
    • 7:46 - Pair
    • 15:05 - Connect
    • 19:01 - Optimize
    • 22:26 - Guidelines

    资源

    • Accessory Design Guidelines
    • Building peer-to-peer apps
    • Wi-Fi Aware
      • 高清视频
      • 标清视频

    相关视频

    WWDC24

    • 了解 AccessorySetupKit
  • 搜索此视频…

    Hi, I’m Swetank. I'm an engineer on the Wi-Fi team. And today, I’ll be introducing the Wi-Fi Aware framework and show how you can use it to supercharge device-to-device interactions in your apps. First, I’ll set the foundation with a quick overview of Wi-Fi Aware. Next, I’ll dive into how you can integrate Wi-Fi Aware in your app.

    Then, I’ll cover how devices can securely discover and pair using the DeviceDiscoveryUI and AccessorySetupKit frameworks. After pairing, I’ll discuss how devices can set up Wi-Fi Aware connections using the Network framework. Once connected, I’ll look at how to monitor and optimize performance of Wi-Fi Aware connections. Finally, I’ll talk about some important next steps. Let’s start with an overview. Wi-Fi Aware enables direct device-to-device communication. Unlike traditional models that rely on routers or central servers, this is truly peer-to-peer.

    These connections are dynamic and on-demand. Devices can find each other and form secure links at runtime. Perfect for local ephemeral experiences like file sharing or setting up an accessory.

    Wi-Fi Aware operates alongside your regular Wi-Fi connection. That means devices stay connected to the internet and your local network while simultaneously using Wi-Fi Aware. And Wi-Fi Aware is a global standard maintained by the Wi-Fi Alliance. It’s cross-platform, interoperable, and can be adopted by any device manufacturer.

    With Wi-Fi Aware, you can unlock new experiences and allow your apps to seamlessly discover and connect to nearby devices. Some examples include: media streaming, high-speed file transfer, accessory control, screen sharing, and if needed, you can do all of these simultaneously.

    Introducing Wi-Fi Aware, a new framework that enables these experiences on iPhone and iPad. With the Wi-Fi Aware framework, your app can connect to other Apple devices, 3rd-party devices, and even accessories.

    When using Wi-Fi Aware, your connections are fully authenticated and encrypted at the Wi-Fi layer, can support high throughput and low latency, and co-exist with connections to other nearby devices at the same time.

    To use Wi-Fi Aware, your app only needs to handle two high-level flows. The first flow is pairing a device.

    Pairing is a one-time setup process that establishes trust and facilitates secure communication. The second flow is connecting paired devices. The system automatically secures the connection between devices, including key exchange and link encryption, so you don’t need to manage security protocols at all. And once paired, your app can securely reconnect whenever your devices are in close proximity and actively running your application.

    This makes connecting back to the device seamless, fast, and secure.

    Now let’s see how you can set up your app to use Wi-Fi Aware. We will start with discussing a central concept for Wi-Fi Aware: services.

    Services are used for discovering devices and connecting to them. Think of services as specific functionality that your app either provides or consumes from other devices. Before we move on to declaring services in your app, let’s first understand a few key conventions for services.

    A service is identified by its name.

    Service names must be unique, only consist of letters, numbers, and dashes, and not be longer than 15 characters.

    There are two parts in a full service name.

    A unique name, followed by a protocol, which can either be tcp for services using TCP, or udp for services using any other protocol.

    To prevent collisions between your apps service names and those used by other apps, you can register service names with IANA.

    Next, let's talk about service roles. Wi-Fi Aware allows for two possible roles for a given service. The first is Publisher, where your app hosts the service and acts as a server, listening for incoming connections from other devices.

    The second is Subscriber, where your app uses the service and acts as the client, browsing for other devices to connect to.

    Your application can simultaneously operate as both publisher and subscriber if required for your use cases.

    Your application’s Info.plist specifies the services it intends to use. To do this, add the WiFiAwareServices key.

    This is a dictionary where keys are service names and the corresponding value is the configuration for that service.

    In this example, the app declares two services: file service and drone service.

    Each service has a dictionary of configuration properties.

    To make a service Publishable, include the Publishable key. And to make it Subscribable, include the Subscribable key. In this case, file service is declared to be both Publishable and Subscribable. This is common when building app-to-app use cases.

    In contrast, drone service is only subscribable, which is a common scenario when developing an app to talk to an accessory. Keep in mind that your app will only be able to publish or subscribe services that have been declared in the Info.plist. Now let's jump into some code and see how to access device capabilities and services that were declared in the Info.plist.

    Before an application uses Wi-Fi Aware, it should first check if it is supported on the device.

    This can be done by checking the supportedFeatures property of WACapabilities.

    Publishable services defined in the Info.plist are made available through WAPublishableService. In the example here, a static property, fileService, is defined for convenient access to the service later on. Subscribable services are accessed via WASubscribableService. For convenience, two static properties are defined to refer to fileService and droneService for later use.

    Now that you know how to add Wi-Fi Aware services to your app, let’s talk about how you can pair Wi-Fi Aware devices. Let’s start by discussing what the pairing flow looks like to a person using your app. As discussed previously, your app will pair Wi-Fi Aware devices prior to using them. Your app can trigger the pairing flow by calling APIs to show the system pairing UI. For the person using your app, pairing then follows a simple process.

    First, the person will be prompted to select a device from a list of nearby devices matching the parameters provided by your app.

    Then, the person will authorize the pairing by entering a PIN code provided by the other device.

    Finally, the system will complete pairing and let the person know when it succeeds. This will make the device available to your app. Once available, your app can make connections to that device on demand without needing to invoke the pairing flow again.

    There are two system frameworks available for pairing devices: DeviceDiscoveryUI and AccessorySetupKit.

    DeviceDiscoveryUI is for making connections between apps and from an app to another device. It supports pairing with both Apple and third-party devices. AccessorySetupKit is for accessory makers to quickly onboard their accessory. It is the recommended framework for hardware accessory makers. Let’s talk about DeviceDiscoveryUI in more detail.

    A person using DeviceDiscoveryUI would start by pressing a button in your app's UI to add or select a device. On the publisher side, your app will call APIs to present the advertiser UI, as seen on the left. On another device, your app will call APIs to present the device picker UI, as seen on the right.

    The browser UI will find nearby devices that match your Wi-Fi Aware service and present them for the person to choose. If the person selects an unpaired device, the system will automatically start the pairing flow.

    When pairing is needed, the incoming request and a PIN code is displayed on the publisher side and entered on the subscriber side.

    Once the person confirms the PIN, the system pairs the devices. Upon completion, your app can make a connection to the other device.

    Now that we have seen the DeviceDiscoveryUI flow, let's look at some code.

    On the listener side, your app will create a DevicePairingView by passing it the service to advertise.

    On the browser side, your app will create a DevicePicker view by passing it the service to discover.

    When a discovered device is tapped, DeviceDiscoveryUI will render connectable network endpoint to your app. If required, DeviceDiscoveryUI will perform pairing before providing the network endpoint.

    If you are an accessory maker, then AccessorySetupKit is the recommended method to pair with your app. If your accessory uses multiple transports, such as Bluetooth and Wi-Fi Aware, AccessorySetupKit will pair and set up both at the same time. Let's take a look at the pairing flow when using AccessorySetupKit with Wi-Fi Aware. A person using AccessorySetupKit would start by pressing a button in your app’s UI to add or select a device. Your app will fill out a discovery descriptor, specifying the service and filters to use for discovering devices. It then presents the AccessorySetupKit UI.

    AccessorySetupKit will find the nearby devices that match your service and discovery filter and present them in the UI. The person then selects the device they wish to set up.

    During the setup, the person enters a PIN to confirm the Wi-Fi Aware pairing. The PIN is displayed on the publisher and entered on the subscriber side.

    The system then performs the pairing on behalf of the app.

    Now that we have seen the AccessorySetupKit flow, let’s look at the code. To pair Wi-Fi Aware devices with AccessorySetupKit, first create an ASDiscoveryDescriptor where you provide the service name and filters for device properties like model and vendor. Then present the AccessorySetupKit UI by creating an ASAccessorySession and calling showPicker on it. The system will take care of the discovery and pairing process. When the pairing is complete, a new ASAccessory will be returned, which represents the newly paired device. This contains a ASAccessoryWiFiAwarePairedDeviceID, which is the ID of the paired device. Your app can use this ID to look up the corresponding WAPairedDevice via the Wi-Fi Aware framework. The device can be used to initiate connection using the Network framework.

    For more information on AccessorySetupKit, see the WWDC24 session “Meet AccessorySetupKit.” Now that I've covered how to pair devices, let's explore how your app can access the list of pair devices.

    Wi-Fi Aware represents a pair device as a WAPairedDevice struct. You can get the list of devices using the allDevices API on WAPairedDevice.

    You can access device properties like vendor and model name, which are learned during pairing.

    The API can either win all devices or the ones that match a provided filter.

    For example, to get all devices matching Example Inc as the vendor name, create a filter as shown here.

    The list of paired devices for your app can change at any time. For instance, if a device is removed from the settings, your app can listen to these changes and update the UI and other state accordingly. The framework provides an easy way to do this by vending an async sequence through WaPairedDevice.allDevices.

    Note that APIs discussed here vend all paired devices available to your app, regardless of whether they are currently reachable or not. Having covered the first high level flow: pairing, let us now focus on the second flow, wherein your application will establish connections with paired devices. Before looking at the code, let’s first understand the high level flow for making a Wi-Fi Aware connection. Making a connection requires two devices. One device publishes the service and listens for connections from specific pair devices.

    The other device subscribes to the service and browses for specific pair devices to connect to. To conserve power, listening and browsing should be limited to the duration necessary for your use case.

    Once the browser discovers the service and device combination you provided, it will vend connectable network endpoints to the app. Next, your application will review the endpoints and establish connections with one or more of them.

    The listener receives the connection request and forwards it to your app, completing the connection. At this point, data can be exchanged.

    Let’s explore how to use the Network framework in your application to establish a Wi-Fi Aware connection.

    Before publishing or subscribing, your app needs to select the paired devices of interest.

    In the example here, publisher creates a filter for devices with names starting with My Device.

    Similarly, the subscribers filter is selecting devices with vendor names starting with Example Inc.

    The necessary parameters are now available to start listener and browser instances using the Network framework.

    To construct a NetworkListener, provide the service object and device filter created earlier.

    The NetworkListener created in this manner will only accept connections for the specified service and pair devices that match the provided filter.

    In addition to Wi-Fi Aware parameters, your application can configure network parameters and set up the state update handler.

    Similarly, the NetworkBrowser is created using the service and device filter from earlier.

    This browser will only discover paired devices that are advertising the service and match the filter.

    Having successfully created a listener and a browser, your app can now establish a connection.

    To begin accepting incoming connections on the listener, invoke the run operation on the listener object.

    Starting the listener makes your app discoverable to other devices.

    To start subscribing for services on the browser, invoke the run operation on the browser object.

    Starting the browser discovers nearby devices offering the service.

    The browser will return the list of discovered devices as network endpoints to your app.

    Your app will then review the discovered endpoints and decide if the endpoint of interest is present.

    Use the NetworkConnection API to start connections to the desired endpoint.

    When the connection is set up, the listener will receive a callback for the new connection, providing it to your app. Your application can now exchange data using Network framework APIs. To conserve wireless resources and power, stop the listener and browser once all the required connections have been made.

    I have covered all the steps required to make a Wi-Fi Aware connection. Next, let’s look at how to optimize connection performance for the best possible app experience. Optimizing performance requires balancing throughput, latency, and power consumption. In most cases, the system will apply reasonable defaults. However, if needed, your app can adjust certain connection parameters.

    One is the Wi-Fi Aware Performance Mode, which influences the Wi-Fi Aware duty cycle.

    The second is the Traffic Service Class, which sets the priority for packet transmission.

    This defaults to best effort but can be set to interactive video or voice for lower latency.

    If you have low-priority data, utilize the background service class to avoid interfering with other traffic.

    Typically, bulk performance mode is used with best effort or background service class. This combination results in lower power consumption, but higher latency.

    On the other hand, real time is used with interactive voice or video service class. This provides lower latency, but more power consumption. Before you decide to use real time mode, consider carefully if it’s required for your use case, as it can negatively impact battery drain. In addition to offering tunable settings for connection performance, Wi-Fi Aware framework also provides an on-demand performance report for each network connection. The performance report includes metrics on signal strength, throughput, and latency. Use this feedback to tune your app’s performance. As Wi-Fi connection strength, environmental interference, and device capabilities can vary significantly in the real world, be sure to test how your app performs in busy Wi-Fi environments. Additionally, incorporate connection feedback from network protocols like TCP in your app.

    Let’s delve into some code and see how you can put the tunable parameters to use. As mentioned earlier, Wi-Fi Aware connections default to bulk performance mode coupled with the best effort service class. If profiling suggests your use case benefits from another configuration, you can set the parameters on the publisher and the connection instance on the subscriber to configure the performance mode and service class.

    In this example, the publisher is set to use real-time performance mode and interactive video traffic service class.

    On the subscriber side, the same configuration is needed on the NetworkConnection object that is created by your App.

    To monitor your app’s Wi-Fi Aware connection, access the current path and read the performance report. Your app can then take actions based on this report and refine the overall user experience.

    Now that I’ve covered all the things you need to build an app using Wi-Fi Aware, I can't wait to see what you come up with. But before we go, let’s talk about some important next steps. If you are a hardware manufacturer, developing a Wi-Fi Aware capable device, refer to the accessory design guidelines to ensure interoperability with Apple devices. The guidelines document is available on the Apple Developer website. Following the guide allows your device to reliably discover and pair with Apple devices, maintain strong security, and maximize connection performance.

    The guide is the best resource for building consistent, high quality Wi-Fi Aware experiences.

    We encourage you to review the Wi-Fi Aware framework documentation for additional details. A sample app is also available which shows how to build an app using Wi-Fi Aware and how different performance configurations impact our behavior.

    Finally, if you are building a Wi-Fi Aware device, the interoperability guide can help you to create the best possible experience for your users.

    Thanks for watching.

    • 6:57 - Access capabilities and services

      import WiFiAware
      
      // Check if Wi-Fi Aware is supported on your device
      guard WACapabilities.supportedFeatures.contains(.wifiAware) else { return }
      
      // Publishable service declared in Info.plist
      extension WAPublishableService {
          public static var fileService: WAPublishableService {
              allServices["_file-service._tcp"]!
          }
      }
      
      // Subscribable services declared in Info.plist
      extension WASubscribableService {
          public static var fileService: WASubscribableService {
              allServices["_file-service._tcp"]!
          }
          public static var droneService: WASubscribableService {
              allServices["_drone-service._udp"]!
          }
      }
    • 10:33 - Pair with DeviceDiscoveryUI

      import DeviceDiscoveryUI
      import WiFiAware
      import SwiftUI
      
      // Listener (Publisher) Device
      // Invoke Listener UI
      DevicePairingView(.wifiAware(.connecting(to: .fileService, from: .selected([])))) {
          // Provide a view to display to user before launching System UI
      } fallback: {
          // Provide a view in case of error
      }
      
      // Browser (Subscriber) Device
      // Invoke Browser UI
      DevicePicker(.wifiAware(.connecting(to: .selected([]), from: .fileService))) { endpoint in
          // Process the paired network endpoint
      } label: {
          // Provide a view to display to user before launching System UI
      } fallback: {
          // Provide a view in case of error
      }
    • 12:29 - Pair with AccessorySetupKit

      import AccessorySetupKit
      
      // Configure ASDiscoveryDescriptor (Subscriber)
      let descriptor = ASDiscoveryDescriptor()
      descriptor.wifiAwareServiceName = "_drone-service._udp"
      descriptor.wifiAwareModelNameMatch = .init(string: "Example Model")
      descriptor.wifiAwareVendorNameMatch = .init(string: "Example Inc", compareOptions: .literal)
      let item = ASPickerDisplayItem(name: "My Drone",
                                     productImage: UIImage(named: "DroneProductImage")!,
                                     descriptor: descriptor)
      
      // Create and activate session
      let session = ASAccessorySession()
      session.activate(on: sessionQueue) { event in
          // Closure will execute when device is added with event: .accessoryAdded
          // ASAccessoryWiFiAwarePairedDeviceID can be used to lookup a WAPairedDevice
      }
      // Present Picker UI
      session.showPicker(for: [item]) { error in
          // Handle error
      }
    • 13:51 - Access paired devices

      import Foundation
      import WiFiAware
      
      // WAPairedDevice
      var device: WAPairedDevice // Get using WAPairedDevice.allDevices
      
      // Access WAPairedDevice properties
      let pairingName = device.pairingInfo?.pairingName
      let vendorName = device.pairingInfo?.vendorName
      let modelName = device.pairingInfo?.modelName
      
      // Create a filter to select devices of interest
      let filter = #Predicate<WAPairedDevice> {
          $0.pairingInfo?.vendorName.starts(with: "Example Inc") ?? false
      }
      
      // Get all paired devices, matching the filter, at the current moment
      // A new snapshot of all paired devices each time a device is added, changed, or removed
      for try await devices in WAPairedDevice.allDevices(matching: filter) {
          // Process new snapshot of all paired devices
      }
    • 16:23 - Filter paired devices

      import Foundation
      import WiFiAware
      
      // Listener (Publisher) Device
      // Specify the paired devices of interest for the use case
      let deviceFilter = #Predicate<WAPairedDevice> {
          $0.name?.starts(with: "My Device") ?? false
      }
      
      // Browser (Subscriber) Device
      // Specify the paired devices of interest for the use case
      let deviceFilter = #Predicate<WAPairedDevice> {
          $0.pairingInfo?.vendorName.starts(with: "Example Inc") ?? false
      }
    • 16:54 - Create listener and browser

      import WiFiAware
      import Network
      
      // Listener (Publisher) Device: Construct a NetworkListener
      let listener = try NetworkListener(for:
              .wifiAware(.connecting(to: .fileService, from: .matching(deviceFilter))),
          using: .parameters {
              TLS()
          })
          .onStateUpdate { listener, state in
              // Process state update
          }
      
      // Browser (Subscriber) Device: Construct a NetworkBrowser
      let browser = NetworkBrowser(for:
              .wifiAware(.connecting(to: .matching(deviceFilter), from: .fileService))
          )
          .onStateUpdate { browser, state in
              // Process state update
          }
    • 17:44 - Establish a connection

      // Listener (Publisher) Device: Start NetworkListener
      try await listener.run { connection in  // Radio resources in use
          // Closure executes for each incoming connection
          connection.onStateUpdate { connection, state in
              // Process state update
          }
      }
      
      // Browser (Subscriber) Device: Start NetworkBrowser
      let endpoint = try await browser.run { waEndpoints in // Radio resources in use
              // Review endpoints, decide whether to return or skip
              if let endpoint = self.endpoint(in: waEndpoints) { return .finish(endpoint) }
              else { return .continue }
          }
      // Create the connection
      let connection = NetworkConnection(to: endpoint, using: .parameters {
              TLS()
          })
          .onStateUpdate { connection, state in
              // Process state update
          }
    • 21:11 - Tune performance

      // Listener (Publisher) Device
      // Configure .realtime + .interactiveVideo on NetworkListener
      let listener = try NetworkListener(for:
              .wifiAware(.connecting(to: .fileService, from: .matching(deviceFilter))),
          using: .parameters {
              TLS()
          }
          .wifiAware { $0.performanceMode = .realtime }
          .serviceClass(.interactiveVideo))
      
      // Browser (Subscriber) Device
      // Configure .realtime + .interactiveVideo on NetworkConnection
      let connection = NetworkConnection(to: endpoint, using: .parameters {
              TLS()
          }
          .wifiAware { $0.performanceMode = .realtime }
          .serviceClass(.interactiveVideo))
      
      // Listener (Publisher) Device & Browser (Subscriber) Device
      // Read performance report
      let performanceReport = try await connection.currentPath?.wifiAware?.performance
    • 0:00 - Introduction
    • Learn how to use Wi-Fi Aware on iOS and iPadOS to create peer-to-peer network connections with low latency and high throughput.

    • 1:01 - Overview
    • Wi-Fi Aware is a standard that enables direct, device-to-device communication without the need for routers or central servers. It operates alongside regular Wi-Fi connections, allowing devices to discover and connect securely and dynamically for local ephemeral experiences such as file sharing, media streaming, accessory control, and screen sharing. Wi-Fi Aware is cross-platform and interoperable, with connections fully authenticated and encrypted. Apps can define services, specify roles as publishers or subscribers (or both), and pair devices for seamless and fast reconnections whenever in close proximity.

    • 7:46 - Pair
    • Devices can be paired using either the DeviceDiscoveryUI framework or AccessorySetupKit framework. DeviceDiscoveryUI is suitable for app-to-app pairing, supporting both Apple and third-party devices. AccessorySetupKit is suitable for app-to-accessory pairing. After devices are paired, both frameworks enable apps to access and manage the list of paired devices, retrieve their properties, and listen for changes in the pairing status, allowing the app to update its UI and state accordingly.

    • 15:05 - Connect
    • When paired, the devices can connect to each other. One device has the publisher role, and the other device has the subscriber role. The publisher filters for specific devices and starts listening, while the subscriber filters and starts browsing. After the subscriber finds the publisher, it provides endpoints to the app, which then establishes connections. The listener receives and forwards these connection requests, enabling data exchange.

    • 19:01 - Optimize
    • To optimize connection performance for an app, the Wi-Fi Aware framework allows developers to adjust certain parameters. The framework provides two main performance modes: bulk and real-time. Bulk mode is energy-efficient but has higher latency, while real-time mode offers lower latency but consumes more power. Developers can also set the traffic service class to prioritize packet transmission, with options for best effort, interactive video or voice, and background service class. The framework offers on-demand performance reports that include metrics on signal strength, throughput, and latency, which developers can use to tune their app's performance based on real-world testing and environmental factors.

    • 22:26 - Guidelines
    • Hardware manufacturers developing Wi-Fi Aware devices can consult Apple's Accessory Design Guidelines on the Developer website for interoperability, security, and performance optimization. The guide, along with the framework documentation and sample app, provides essential resources for creating high-quality user experiences.

Developer Footer

  • 视频
  • WWDC25
  • 借助 Wi-Fi Aware 增强设备连接性能
  • 打开菜单 关闭菜单
    • 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. 保留所有权利。
    使用条款 隐私政策 协议和准则